현재 udp통신을 구현 중인데 클라이언트에서 서버로 send(button1) 버튼을 누르면, 접속 종료라는 버튼이 서버에 뜨고, 그 반대의 경우는 send버튼을 누르면 서버가 꺼지고 클라이언트에는 아무런 표시가 안남습니다. 그리고 둘 다 close(button2) 버튼을 누를 경우, 런타임 에러가 뜹니다. 어느 부분이 문제이고, 어떤 부분을 수정해야 서로 간에 데이터를 주고받을 수 있는지, 종료가 정상적으로 되는지 수정된 코드와 함께 알려주세요. 참고로 이 코드에는 체크섬과 arq도 구현을 하려고 합니다.
서버 부분
#include "pch.h"
#include "framework.h"
#include "UDPServerthd.h"
#include "UDPServerthdDlg.h"
#include "afxdialogex.h"
#include "CDataSocket.h"
CDataSocket* m_pDataSocket;
CString save_message;
CCriticalSection tx_cs;
CCriticalSection rx_cs;
UINT senPort = 19000;
UINT desPort = 17000;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 응용 프로그램 정보에 사용되는 CAboutDlg 대화 상자입니다.
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.
// 구현입니다.
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CUDPServerthdDlg 대화 상자
CUDPServerthdDlg::CUDPServerthdDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_UDPSERVERTHD_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CUDPServerthdDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_EDIT1, m_tx_edit_short);
DDX_Control(pDX, IDC_EDIT2, m_tx_edit);
DDX_Control(pDX, IDC_EDIT3, m_rx_edit);
}
BEGIN_MESSAGE_MAP(CUDPServerthdDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CUDPServerthdDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CUDPServerthdDlg::OnBnClickedButton2)
END_MESSAGE_MAP()
// CUDPServerthdDlg 메시지 처리기
UINT TIMERThread(LPVOID run) {
Sleep(3000);
*(bool*)run = FALSE;
return 0;
}
UINT TXThread(LPVOID arg) {
ThreadArg* pArg = (ThreadArg*)arg;
CStringList* pList = pArg->pList;
CUDPServerthdDlg* pDlg = (CUDPServerthdDlg*)pArg->pDlg;
Packet pkt;
CWinThread* pTime;
CList<Packet>* pACK = pArg->pAck;
while (pArg->Thread_run) {
POSITION pos = pList->GetHeadPosition();
POSITION current_pos;
while (pos != NULL) {
current_pos = pos;
tx_cs.Lock();
CString str = pList->GetNext(pos);
tx_cs.Unlock();
CString message;
pDlg->m_tx_edit_short.GetWindowText(message);
message += str + _T("\r\n");
pDlg->m_tx_edit.SetWindowTextW(message);
pDlg->m_tx_edit.LineScroll(pDlg->m_tx_edit.GetLineCount());
pDlg->m_tx_edit.SetFocus();
CStringA strA(message);
const char* msg = strA;
char pktMsg[1024];
strncpy_s(pktMsg, msg, sizeof(pktMsg));
for (int i = 0; i < strlen(msg) / 16 + 1; i++) {
memcpy(pkt.data, msg + i * 16, 16);
pkt.sequence = i;
if (i == strlen(msg) / 16)
pkt.max_seq = i;
pkt.checksum = pDlg->Checksum(&pkt);
m_pDataSocket->SendToEx(&pkt, sizeof(Packet), desPort, pDlg->PeerAddr);
int ack_state = 2;
while (ack_state == 2) {
bool run = true;
pTime = AfxBeginThread(TIMERThread,(LPVOID) & run);
while (run == true) {
POSITION pos2 = pACK->GetHeadPosition();
POSITION current_pos2;
while (pos2 != NULL) {
current_pos2 = pos2;
Packet ack = pACK->GetNext(pos2);
ack_state = ack.ack;
run = false;
pACK->RemoveAt(current_pos2);
}
}
if (ack_state == 2)
m_pDataSocket->SendToEx(&pkt, sizeof(Packet), desPort, pDlg->PeerAddr);
}
}
pList->RemoveAt(current_pos);
}
Sleep(10);
}
return 0;
}
UINT RXThread(LPVOID arg) {
ThreadArg* pArg = (ThreadArg*)arg;
CStringList* plist = pArg->pList;
CUDPServerthdDlg* pDlg = (CUDPServerthdDlg*)pArg->pDlg;
while (pArg->Thread_run) {
POSITION pos = plist->GetHeadPosition();
POSITION current_pos;
while (pos != NULL) {
current_pos = pos;
rx_cs.Lock();
CString str = plist->GetNext(pos);
rx_cs.Unlock();
CString message;
pDlg->m_rx_edit.GetWindowText(message);
message += str;
pDlg->m_rx_edit.SetWindowText(message);
pDlg->m_rx_edit.LineScroll(pDlg->m_rx_edit.GetLineCount());
plist->RemoveAt(current_pos);
}
Sleep(10);
}
return 0;
}
BOOL CUDPServerthdDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 시스템 메뉴에 "정보..." 메뉴 항목을 추가합니다.
// IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
// 프레임워크가 이 작업을 자동으로 수행합니다.
SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다.
SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다.
// TODO: 여기에 추가 초기화 작업을 추가합니다.
WSADATA wsa;
int error_code;
if ((error_code = WSAStartup(MAKEWORD(2, 2), &wsa)) != 0) {
TCHAR buffer[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, 256, NULL);
AfxMessageBox(buffer, MB_ICONERROR);
}
m_pDataSocket = NULL;
m_pDataSocket = new CDataSocket(this);
m_pDataSocket->Create(senPort, SOCK_DGRAM);
CStringList* newlist = new CStringList;
arg1.pList = newlist;
arg1.Thread_run = 1;
arg1.pDlg = this;
CStringList* newlist2 = new CStringList;
arg2.pList = newlist2;
arg2.Thread_run = 1;
arg2.pDlg = this;
CList<Packet>* pACK = new CList<Packet>;
arg1.pAck = pACK;
pThread1 = AfxBeginThread(TXThread, (LPVOID)&arg1);
pThread2 = AfxBeginThread(TXThread, (LPVOID)&arg2);
return TRUE;
AfxMessageBox(_T("이미 실행 중인 서버가 있습니다."), MB_ICONERROR);
return FALSE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}
void CUDPServerthdDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
// 아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 애플리케이션의 경우에는
// 프레임워크에서 이 작업을 자동으로 수행합니다.
void CUDPServerthdDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 아이콘을 그립니다.
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
// 이 함수를 호출합니다.
HCURSOR CUDPServerthdDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CUDPServerthdDlg::ProcessReceive(CDataSocket* pSocket, int nErrorCode)
{
if (pSocket == nullptr)
return;
static CString strData;
int nbytes;
Packet pkt;
int datasum = 0;
Packet ack_pkt;
nbytes = pSocket->ReceiveFromEx(&pkt, sizeof(Packet), PeerAddr, desPort);
for (int i = 0; i < strlen(pkt.data); i++) {
datasum += pkt.data[i];
}
char pBuf[17];
memcpy(pBuf, pkt.data, 16);
pBuf[16] = NULL;
if ((pkt.ack == 1) || (pkt.ack == 2)) {
arg1.pAck->AddTail(pkt);
}
else {
if (pkt.sequence != pkt.max_seq) {
if (datasum + pkt.checksum == 0) {
strData += pBuf;
ack_pkt.ack = 1;
ack_pkt.sequence = pkt.sequence;
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
}
else {
ack_pkt.ack = 2;
ack_pkt.sequence = pkt.sequence;
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
}
}
else {
if (datasum + pkt.checksum == 0) {
strData += pBuf;
ack_pkt.ack = 1;
ack_pkt.sequence = pkt.sequence;
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
rx_cs.Lock();
arg2.pList->AddTail((LPCTSTR)strData);
rx_cs.Unlock();
strData = _T("");
}
else {
ack_pkt.ack = 2;
ack_pkt.sequence = pkt.sequence;
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
}
}
}
}
void CUDPServerthdDlg::ProcessClose(CDataSocket* pSocket, int nErrorCode)
{
if (pSocket == nullptr)
return;
// TODO: 여기에 구현 코드 추가.
pSocket->Close();
delete m_pDataSocket;
m_pDataSocket = nullptr;
int len = m_rx_edit.GetWindowTextLengthW();
CString tx_Message = _T("##접속종료##\r\n");
m_rx_edit.SetSel(len, len);
m_rx_edit.ReplaceSel(tx_Message);
}
void CUDPServerthdDlg::OnBnClickedButton1()
{
CString tx_message;
m_tx_edit_short.GetWindowText(tx_message);
send_message += tx_message + _T("\r\n");
tx_cs.Lock();
arg1.pList->AddTail(tx_message);
tx_cs.Unlock();
m_tx_edit_short.SetWindowTextW(_T(""));
m_tx_edit.SetWindowTextW(send_message);
}
void CUDPServerthdDlg::OnBnClickedButton2()
{
if (m_pDataSocket == NULL) {
AfxMessageBox(_T("이미 접속 종료"));
}
else {
arg1.Thread_run = 0;
arg2.Thread_run = 2;
m_pDataSocket->Close();
delete m_pDataSocket;
m_pDataSocket = NULL;
}
if (pThread1 != nullptr)
AfxEndThread(pThread1->m_nThreadID);
if (pThread2 != nullptr)
AfxEndThread(pThread2->m_nThreadID);
// 프로그램 종료
OnOK();;
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
}
int CUDPServerthdDlg::Checksum(Packet* pkt)
{
int checksum = 0;
for (int i = 0; i < strlen(pkt->data); i++) {
checksum += pkt->data[i];
}
checksum = -(checksum);
// TODO: 여기에 구현 코드 추가.
return checksum;
}
클라이언트 부분
#include "pch.h"
#include "framework.h"
#include "UDPClientthd.h"
#include "UDPClientthdDlg.h"
#include "afxdialogex.h"
#include "CDataSocket.h"
CDataSocket* m_pDataSocket;
CString save_message;
CCriticalSection tx_cs;
CCriticalSection rx_cs;
UINT senPort = 17000;
UINT desPort = 19000;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 응용 프로그램 정보에 사용되는 CAboutDlg 대화 상자입니다.
struct ThreadArg;
ThreadArg arg1, arg2;
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.
// 구현입니다.
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CUDPClientthdDlg 대화 상자
CUDPClientthdDlg::CUDPClientthdDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_UDPCLIENTTHD_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CUDPClientthdDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_EDIT2, m_tx_edit);
DDX_Control(pDX, IDC_EDIT1, m_tx_edit_short);
DDX_Control(pDX, IDC_EDIT3, m_rx_edit);
DDX_Control(pDX, IDC_IPADDRESS1, m_ipaddr);
}
BEGIN_MESSAGE_MAP(CUDPClientthdDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CUDPClientthdDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CUDPClientthdDlg::OnBnClickedButton2)
END_MESSAGE_MAP()
// CUDPClientthdDlg 메시지 처리기
UINT TIMERThread(LPVOID run) {
Sleep(3000);
*(bool*)run = FALSE;
return 0;
}
UINT TXThread(LPVOID arg) {
ThreadArg* pArg = (ThreadArg*)arg;
CStringList* pList = pArg->pList;
CUDPClientthdDlg* pDlg = (CUDPClientthdDlg*)pArg->pDlg;
Packet pkt;
CWinThread* pTime;
CList<Packet>* pACK = pArg->pAck;
while (pArg->Thread_run) {
POSITION pos = pList->GetHeadPosition();
POSITION current_pos;
while (pos != NULL) {
current_pos = pos;
tx_cs.Lock();
CString str = pList->GetNext(pos);
tx_cs.Unlock();
CString message;
pDlg->m_tx_edit_short.GetWindowText(message);
message += str + _T("\r\n");
pDlg->m_tx_edit.SetWindowTextW(message);
pDlg->m_tx_edit.LineScroll(pDlg->m_tx_edit.GetLineCount());
pDlg->m_tx_edit.SetFocus();
CStringA strA(message);
const char* msg = strA;
char pktMsg[1024];
strncpy_s(pktMsg, msg, sizeof(pktMsg));
for (int i = 0; i < strlen(msg) / 16 + 1; i++) {
memcpy(pkt.data, msg + i * 16, 16);
pkt.sequence = i;
if (i == strlen(msg) / 16)
pkt.max_seq = i;
pkt.checksum = pDlg->Checksum(&pkt);
m_pDataSocket->SendToEx(&pkt, sizeof(Packet), desPort, pDlg->PeerAddr);
int ack_state = 2;
while (ack_state == 2) {
bool run = true;
pTime = AfxBeginThread(TIMERThread,(LPVOID) & run);
while (run == true) {
POSITION pos2 = pACK->GetHeadPosition();
POSITION current_pos2;
while (pos2 != NULL) {
current_pos2 = pos2;
Packet ack = pACK->GetNext(pos2);
ack_state = ack.ack;
run = false;
pACK->RemoveAt(current_pos2);
}
}
if (ack_state == 2)
m_pDataSocket->SendToEx(&pkt, sizeof(Packet), desPort, pDlg->PeerAddr);
}
}
pList->RemoveAt(current_pos);
}
Sleep(10);
}
return 0;
}
UINT RXThread(LPVOID arg) {
ThreadArg* pArg = (ThreadArg*)arg;
CStringList* plist = pArg->pList;
CUDPClientthdDlg* pDlg = (CUDPClientthdDlg*)pArg->pDlg;
while (pArg->Thread_run) {
POSITION pos = plist->GetHeadPosition();
POSITION current_pos;
while (pos != NULL) {
current_pos = pos;
rx_cs.Lock();
CString str = plist->GetNext(pos);
rx_cs.Unlock();
CString message;
pDlg->m_rx_edit.GetWindowText(message);
message += str;
pDlg->m_rx_edit.SetWindowText(message);
pDlg->m_rx_edit.LineScroll(pDlg->m_rx_edit.GetLineCount());
plist->RemoveAt(current_pos);
}
Sleep(10);
}
return 0;
}
BOOL CUDPClientthdDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 시스템 메뉴에 "정보..." 메뉴 항목을 추가합니다.
// IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
// 프레임워크가 이 작업을 자동으로 수행합니다.
SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다.
SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다.
// TODO: 여기에 추가 초기화 작업을 추가합니다.
m_ipaddr.SetWindowTextW(_T("127.0.0.1"));
CStringList* newlist = new CStringList;
arg1.pList = newlist;
arg1.Thread_run = 1;
arg1.pDlg = this;
CStringList* newlist2 = new CStringList;
arg2.pList = newlist2;
arg2.Thread_run = 1;
arg2.pDlg = this;
CList<Packet>* pACK = new CList<Packet>;
arg1.pAck = pACK;
WSADATA wsa;
int error_code;
if ((error_code = WSAStartup(MAKEWORD(2, 2), &wsa)) != 0) {
TCHAR buffer[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, 256, NULL);
AfxMessageBox(buffer, MB_ICONERROR);
}
m_pDataSocket = new CDataSocket(this);
m_pDataSocket->Create(senPort, SOCK_DGRAM);
pThread1 = AfxBeginThread(TXThread, (LPVOID)&arg1);
pThread2 = AfxBeginThread(TXThread, (LPVOID)&arg2);
return TRUE;
AfxMessageBox(_T("이미 실행 중인 서버가 있습니다."), MB_ICONERROR);
return FALSE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}
void CUDPClientthdDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
// 아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 애플리케이션의 경우에는
// 프레임워크에서 이 작업을 자동으로 수행합니다.
void CUDPClientthdDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 아이콘을 그립니다.
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
// 이 함수를 호출합니다.
HCURSOR CUDPClientthdDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CUDPClientthdDlg::ProcessReceive(CDataSocket* pSocket, int nErrorCode)
{
if (pSocket == nullptr)
return;
// TODO: 여기에 구현 코드 추가.
static CString strData;
int nbytes;
Packet pkt;
int datasum = 0;
Packet ack_pkt;
nbytes = pSocket->ReceiveFromEx(&pkt, sizeof(Packet), PeerAddr, desPort);
for (int i = 0; i < strlen(pkt.data); i++) {
datasum += pkt.data[i];
}
char pBuf[17];
memcpy(pBuf, pkt.data, 16);
pBuf[16] = NULL;
if ((pkt.ack == 1) || (pkt.ack == 2)) {
arg1.pAck->AddTail(pkt);
}
else {
if (pkt.sequence != pkt.max_seq) {
if (datasum + pkt.checksum == 0) {
strData += pBuf;
ack_pkt.ack = 1;
ack_pkt.sequence = pkt.sequence;
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
}
else {
ack_pkt.ack = 2;
ack_pkt.sequence = pkt.sequence;
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
}
}
else {
if (datasum + pkt.checksum == 0) {
strData += pBuf;
ack_pkt.ack = 1;
ack_pkt.sequence = pkt.sequence;
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
rx_cs.Lock();
arg2.pList->AddTail((LPCTSTR)strData);
rx_cs.Unlock();
strData = _T("");
}
else {
ack_pkt.ack = 2;
ack_pkt.sequence = pkt.sequence;
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
}
}
}
}
void CUDPClientthdDlg::ProcessClose(CDataSocket* pSocket, int nErrorCode)
{
if (pSocket == nullptr)
return;
// TODO: 여기에 구현 코드 추가.
pSocket->Close();
delete m_pDataSocket;
m_pDataSocket = nullptr;
int len = m_rx_edit.GetWindowTextLengthW();
CString tx_Message = _T("##접속종료##\r\n");
m_rx_edit.SetSel(len, len);
m_rx_edit.ReplaceSel(tx_Message);
}
void CUDPClientthdDlg::OnBnClickedButton1()
{
CString tx_message;
m_tx_edit_short.GetWindowText(tx_message);
send_message += tx_message + _T("\r\n");
tx_cs.Lock();
arg1.pList->AddTail(tx_message);
tx_cs.Unlock();
m_tx_edit_short.SetWindowTextW(_T(""));
m_tx_edit.SetWindowTextW(send_message);
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
}
void CUDPClientthdDlg::OnBnClickedButton2()
{
if (m_pDataSocket == NULL) {
AfxMessageBox(_T("이미 접속 종료"));
}
else {
arg1.Thread_run = 0;
arg2.Thread_run = 2;
m_pDataSocket->Close();
delete m_pDataSocket;
m_pDataSocket = nullptr;
}
if (pThread1 != nullptr)
AfxEndThread(pThread1->m_nThreadID);
if (pThread2 != nullptr)
AfxEndThread(pThread2->m_nThreadID);
// 프로그램 종료
OnOK();
}
int CUDPClientthdDlg::Checksum(Packet* pkt)
{
int checksum = 0;
for (int i = 0; i < strlen(pkt->data); i++) {
checksum += pkt->data[i];
}
checksum = -(checksum);
// TODO: 여기에 구현 코드 추가.
return checksum;
}
서버의 헤더부분
#include "afxcoll.h"
#include "afxwin.h"
#pragma once
struct Packet {
int checksum;
int max_seq;
int ack;
int sequence;
char data[1024];
// 필요한 필드들을 추가할 수 있습니다.
};
struct ThreadArg {
CStringList* pList;
CDialogEx* pDlg;
CList<Packet>* pAck;
BOOL Thread_run;
};
class CDataSocket;
// CUDPServerthdDlg 대화 상자
class CUDPServerthdDlg : public CDialogEx
{
// 생성입니다.
public:
CUDPServerthdDlg(CWnd* pParent = nullptr); // 표준 생성자입니다.
// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_UDPSERVERTHD_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.
// 구현입니다.
protected:
HICON m_hIcon;
// 생성된 메시지 맵 함수
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CWinThread* pThread1, * pThread2;
ThreadArg arg1, arg2;
CDataSocket* m_pDataSocket;
CString PeerAddr;
CString send_message;;
CEdit m_tx_edit_short;
CEdit m_tx_edit;
CEdit m_rx_edit;
void ProcessReceive(CDataSocket* pSocket, int nErrorCode);
void ProcessClose(CDataSocket* pSocket, int nErrorCode);
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton2();
int Checksum(Packet* pkt);
};
클라이언의 헤더 부분
#pragma once
#include "afxcoll.h"
#include "afxwin.h"
struct Packet {
int checksum;
int max_seq;
int ack;
int sequence;
char data[1024];
// 필요한 필드들을 추가할 수 있습니다.
};
struct ThreadArg {
CStringList* pList;
CDialogEx* pDlg;
CList<Packet>* pAck;
BOOL Thread_run;
};
class CDataSocket;
// CUDPClientthdDlg 대화 상자
class CUDPClientthdDlg : public CDialogEx
{
// 생성입니다.
public:
CUDPClientthdDlg(CWnd* pParent = nullptr); // 표준 생성자입니다.
// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_UDPCLIENTTHD_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.
// 구현입니다.
protected:
HICON m_hIcon;
// 생성된 메시지 맵 함수
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CWinThread* pThread1, * pThread2;
ThreadArg arg1, arg2;
CString PeerAddr;
CString send_message;
CEdit m_tx_edit;
CEdit m_tx_edit_short;
CEdit m_rx_edit;
void ProcessReceive(CDataSocket* pSocket, int nErrorCode);
void ProcessClose(CDataSocket* pSocket, int nErrorCode);
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton2();
CIPAddressCtrl m_ipaddr;
int Checksum(Packet* pkt);
};
클라이언트의 헤더 부분