Error: INSERT INTO `kin_1_10405` (subject, seo_subject, content, page, description, og_image, time) VALUES ('mfc기반 udp통신 오류', 'mfc%EA%B8%B0%EB%B0%98+udp%ED%86%B5%EC%8B%A0+%EC%98%A4%EB%A5%98', '
\n \n \n 현재 udp통신을 구현 중인데 클라이언트에서 서버로 send(button1) 버튼을 누르면, 접속 종료라는 버튼이 서버에 뜨고, 그 반대의 경우는 send버튼을 누르면 서버가 꺼지고 클라이언트에는 아무런 표시가 안남습니다. 그리고 둘 다 close(button2) 버튼을 누를 경우, 런타임 에러가 뜹니다. 어느 부분이 문제이고, 어떤 부분을 수정해야 서로 간에 데이터를 주고받을 수 있는지, 종료가 정상적으로 되는지 수정된 코드와 함께 알려주세요. 참고로 이 코드에는 체크섬과 arq도 구현을 하려고 합니다.
서버 부분
\n
\n
#include \"pch.h\"
\n
#include \"framework.h\"
\n
#include \"UDPServerthd.h\"
\n
#include \"UDPServerthdDlg.h\"
\n
#include \"afxdialogex.h\"
\n
#include \"CDataSocket.h\"
\n
CDataSocket* m_pDataSocket;
\n
CString save_message;
\n

\n
CCriticalSection tx_cs;
\n
CCriticalSection rx_cs;
\n

\n
UINT senPort = 19000;
\n
UINT desPort = 17000;
\n
#ifdef _DEBUG
\n
#define new DEBUG_NEW
\n
#endif
\n

\n
// 응용 프로그램 정보에 사용되는 CAboutDlg 대화 상자입니다.
\n

\n
class CAboutDlg : public CDialogEx
\n
{
\n
public:
\n
CAboutDlg();
\n
// 대화 상자 데이터입니다.
\n
#ifdef AFX_DESIGN_TIME
\n
enum { IDD = IDD_ABOUTBOX };
\n
#endif
\n

\n
protected:
\n
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 지원입니다.
\n

\n
// 구현입니다.
\n
protected:
\n
DECLARE_MESSAGE_MAP()
\n
};
\n

\n
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
\n
{
\n
}
\n

\n
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
\n
{
\n
CDialogEx::DoDataExchange(pDX);
\n
}
\n

\n
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
\n
END_MESSAGE_MAP()
\n

\n

\n
// CUDPServerthdDlg 대화 상자
\n

\n

\n

\n
CUDPServerthdDlg::CUDPServerthdDlg(CWnd* pParent /*=nullptr*/)
\n
: CDialogEx(IDD_UDPSERVERTHD_DIALOG, pParent)
\n
{
\n
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
\n
}
\n

\n
void CUDPServerthdDlg::DoDataExchange(CDataExchange* pDX)
\n
{
\n
CDialogEx::DoDataExchange(pDX);
\n
DDX_Control(pDX, IDC_EDIT1, m_tx_edit_short);
\n
DDX_Control(pDX, IDC_EDIT2, m_tx_edit);
\n
DDX_Control(pDX, IDC_EDIT3, m_rx_edit);
\n
}
\n

\n
BEGIN_MESSAGE_MAP(CUDPServerthdDlg, CDialogEx)
\n
ON_WM_SYSCOMMAND()
\n
ON_WM_PAINT()
\n
ON_WM_QUERYDRAGICON()
\n
ON_BN_CLICKED(IDC_BUTTON1, &CUDPServerthdDlg::OnBnClickedButton1)
\n
ON_BN_CLICKED(IDC_BUTTON2, &CUDPServerthdDlg::OnBnClickedButton2)
\n
END_MESSAGE_MAP()
\n

\n

\n
// CUDPServerthdDlg 메시지 처리기
\n
UINT TIMERThread(LPVOID run) {
\n
Sleep(3000);
\n
*(bool*)run = FALSE;
\n
return 0;
\n
}
\n

\n
UINT TXThread(LPVOID arg) {
\n
ThreadArg* pArg = (ThreadArg*)arg;
\n
CStringList* pList = pArg->pList;
\n
CUDPServerthdDlg* pDlg = (CUDPServerthdDlg*)pArg->pDlg;
\n
Packet pkt;
\n
CWinThread* pTime;
\n
CList<Packet>* pACK = pArg->pAck;
\n

\n
while (pArg->Thread_run) {
\n
POSITION pos = pList->GetHeadPosition();
\n
POSITION current_pos;
\n
while (pos != NULL) {
\n
current_pos = pos;
\n
tx_cs.Lock();
\n
CString str = pList->GetNext(pos);
\n
tx_cs.Unlock();
\n

\n
CString message;
\n
pDlg->m_tx_edit_short.GetWindowText(message);
\n
message += str + _T(\"\\r\\n\");
\n
pDlg->m_tx_edit.SetWindowTextW(message);
\n
pDlg->m_tx_edit.LineScroll(pDlg->m_tx_edit.GetLineCount());
\n
pDlg->m_tx_edit.SetFocus();
\n
CStringA strA(message);
\n
const char* msg = strA;
\n

\n
char pktMsg[1024];
\n
strncpy_s(pktMsg, msg, sizeof(pktMsg));
\n
for (int i = 0; i < strlen(msg) / 16 + 1; i++) {
\n
memcpy(pkt.data, msg + i * 16, 16);
\n
pkt.sequence = i;
\n
if (i == strlen(msg) / 16)
\n
pkt.max_seq = i;
\n
pkt.checksum = pDlg->Checksum(&pkt);
\n
m_pDataSocket->SendToEx(&pkt, sizeof(Packet), desPort, pDlg->PeerAddr);
\n

\n
int ack_state = 2;
\n
while (ack_state == 2) {
\n
bool run = true;
\n
pTime = AfxBeginThread(TIMERThread,(LPVOID) & run);
\n
while (run == true) {
\n
POSITION pos2 = pACK->GetHeadPosition();
\n
POSITION current_pos2;
\n
while (pos2 != NULL) {
\n
current_pos2 = pos2;
\n
Packet ack = pACK->GetNext(pos2);
\n
ack_state = ack.ack;
\n
run = false;
\n
pACK->RemoveAt(current_pos2);
\n
}
\n
}
\n
if (ack_state == 2)
\n
m_pDataSocket->SendToEx(&pkt, sizeof(Packet), desPort, pDlg->PeerAddr);
\n
}
\n
}
\n
pList->RemoveAt(current_pos);
\n
}
\n
Sleep(10);
\n
}
\n
return 0;
\n
}
\n

\n
UINT RXThread(LPVOID arg) {
\n
ThreadArg* pArg = (ThreadArg*)arg;
\n
CStringList* plist = pArg->pList;
\n
CUDPServerthdDlg* pDlg = (CUDPServerthdDlg*)pArg->pDlg;
\n

\n
while (pArg->Thread_run) {
\n
POSITION pos = plist->GetHeadPosition();
\n
POSITION current_pos;
\n
while (pos != NULL) {
\n
current_pos = pos;
\n
rx_cs.Lock();
\n
CString str = plist->GetNext(pos);
\n
rx_cs.Unlock();
\n

\n
CString message;
\n
pDlg->m_rx_edit.GetWindowText(message);
\n
message += str;
\n
pDlg->m_rx_edit.SetWindowText(message);
\n
pDlg->m_rx_edit.LineScroll(pDlg->m_rx_edit.GetLineCount());
\n
plist->RemoveAt(current_pos);
\n
}
\n
Sleep(10);
\n
}
\n
return 0;
\n
}
\n
BOOL CUDPServerthdDlg::OnInitDialog()
\n
{
\n
CDialogEx::OnInitDialog();
\n

\n
// 시스템 메뉴에 \"정보...\" 메뉴 항목을 추가합니다.
\n

\n
// IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
\n
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
\n
ASSERT(IDM_ABOUTBOX < 0xF000);
\n
\n
CMenu* pSysMenu = GetSystemMenu(FALSE);
\n
if (pSysMenu != nullptr)
\n
{
\n
BOOL bNameValid;
\n
CString strAboutMenu;
\n
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
\n
ASSERT(bNameValid);
\n
if (!strAboutMenu.IsEmpty())
\n
{
\n
pSysMenu->AppendMenu(MF_SEPARATOR);
\n
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
\n
}
\n
}
\n

\n
// 이 대화 상자의 아이콘을 설정합니다.  응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
\n
//  프레임워크가 이 작업을 자동으로 수행합니다.
\n
SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다.
\n
SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다.
\n

\n
// TODO: 여기에 추가 초기화 작업을 추가합니다.
\n
WSADATA wsa;
\n
int error_code;
\n
if ((error_code = WSAStartup(MAKEWORD(2, 2), &wsa)) != 0) {
\n
TCHAR buffer[256];
\n
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, 256, NULL);
\n
AfxMessageBox(buffer, MB_ICONERROR);
\n
}
\n
m_pDataSocket = NULL;
\n
m_pDataSocket = new CDataSocket(this);
\n
m_pDataSocket->Create(senPort, SOCK_DGRAM);
\n

\n
CStringList* newlist = new CStringList;
\n
arg1.pList = newlist;
\n
arg1.Thread_run = 1;
\n
arg1.pDlg = this;
\n

\n
CStringList* newlist2 = new CStringList;
\n
arg2.pList = newlist2;
\n
arg2.Thread_run = 1;
\n
arg2.pDlg = this;
\n

\n
CList<Packet>* pACK = new CList<Packet>;
\n
arg1.pAck = pACK;
\n

\n
pThread1 = AfxBeginThread(TXThread, (LPVOID)&arg1);
\n
pThread2 = AfxBeginThread(TXThread, (LPVOID)&arg2);
\n
return TRUE;
\n
AfxMessageBox(_T(\"이미 실행 중인 서버가 있습니다.\"), MB_ICONERROR);
\n
return FALSE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
\n
}
\n

\n
void CUDPServerthdDlg::OnSysCommand(UINT nID, LPARAM lParam)
\n
{
\n
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
\n
{
\n
CAboutDlg dlgAbout;
\n
dlgAbout.DoModal();
\n
}
\n
else
\n
{
\n
CDialogEx::OnSysCommand(nID, lParam);
\n
}
\n
}
\n

\n
// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
\n
//  아래 코드가 필요합니다.  문서/뷰 모델을 사용하는 MFC 애플리케이션의 경우에는
\n
//  프레임워크에서 이 작업을 자동으로 수행합니다.
\n

\n
void CUDPServerthdDlg::OnPaint()
\n
{
\n
if (IsIconic())
\n
{
\n
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
\n

\n
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
\n

\n
// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
\n
int cxIcon = GetSystemMetrics(SM_CXICON);
\n
int cyIcon = GetSystemMetrics(SM_CYICON);
\n
CRect rect;
\n
GetClientRect(&rect);
\n
int x = (rect.Width() - cxIcon + 1) / 2;
\n
int y = (rect.Height() - cyIcon + 1) / 2;
\n

\n
// 아이콘을 그립니다.
\n
dc.DrawIcon(x, y, m_hIcon);
\n
}
\n
else
\n
{
\n
CDialogEx::OnPaint();
\n
}
\n
}
\n

\n
// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
\n
//  이 함수를 호출합니다.
\n
HCURSOR CUDPServerthdDlg::OnQueryDragIcon()
\n
{
\n
return static_cast<HCURSOR>(m_hIcon);
\n
}
\n

\n

\n

\n
void CUDPServerthdDlg::ProcessReceive(CDataSocket* pSocket, int nErrorCode)
\n
{
\n
if (pSocket == nullptr)
\n
return;
\n
static CString strData;
\n
int nbytes;
\n
Packet pkt;
\n
int datasum = 0;
\n
Packet ack_pkt;
\n
nbytes = pSocket->ReceiveFromEx(&pkt, sizeof(Packet), PeerAddr, desPort);
\n
for (int i = 0; i < strlen(pkt.data); i++) {
\n
datasum += pkt.data[i];
\n
}
\n
char pBuf[17];
\n
memcpy(pBuf, pkt.data, 16);
\n
pBuf[16] = NULL;
\n

\n
if ((pkt.ack == 1) || (pkt.ack == 2)) {
\n
arg1.pAck->AddTail(pkt);
\n
}
\n
else {
\n
if (pkt.sequence != pkt.max_seq) {
\n
if (datasum + pkt.checksum == 0) {
\n
strData += pBuf;
\n
ack_pkt.ack = 1;
\n
ack_pkt.sequence = pkt.sequence;
\n
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
\n
}
\n
else {
\n
ack_pkt.ack = 2;
\n
ack_pkt.sequence = pkt.sequence;
\n
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
\n
}
\n
}
\n
else {
\n
if (datasum + pkt.checksum == 0) {
\n
strData += pBuf;
\n
ack_pkt.ack = 1;
\n
ack_pkt.sequence = pkt.sequence;
\n
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
\n
rx_cs.Lock();
\n
arg2.pList->AddTail((LPCTSTR)strData);
\n
rx_cs.Unlock();
\n
strData = _T(\"\");
\n
}
\n
else {
\n
ack_pkt.ack = 2;
\n
ack_pkt.sequence = pkt.sequence;
\n
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
\n
}
\n
}
\n
}
\n
}
\n

\n

\n
void CUDPServerthdDlg::ProcessClose(CDataSocket* pSocket, int nErrorCode)
\n
{
\n
if (pSocket == nullptr)
\n
return;
\n
// TODO: 여기에 구현 코드 추가.
\n
pSocket->Close();
\n
delete m_pDataSocket;
\n
m_pDataSocket = nullptr;
\n
int len = m_rx_edit.GetWindowTextLengthW();
\n
CString tx_Message = _T(\"##접속종료##\\r\\n\");
\n
m_rx_edit.SetSel(len, len);
\n
m_rx_edit.ReplaceSel(tx_Message);
\n
}
\n

\n

\n
void CUDPServerthdDlg::OnBnClickedButton1()
\n
{
\n
CString tx_message;
\n
m_tx_edit_short.GetWindowText(tx_message);
\n
send_message += tx_message + _T(\"\\r\\n\");
\n

\n
tx_cs.Lock();
\n
arg1.pList->AddTail(tx_message);
\n
tx_cs.Unlock();
\n

\n
m_tx_edit_short.SetWindowTextW(_T(\"\"));
\n
m_tx_edit.SetWindowTextW(send_message);
\n
}
\n

\n

\n
void CUDPServerthdDlg::OnBnClickedButton2()
\n
{
\n
if (m_pDataSocket == NULL) {
\n
AfxMessageBox(_T(\"이미 접속 종료\"));
\n
}
\n
else {
\n
arg1.Thread_run = 0;
\n
arg2.Thread_run = 2;
\n
m_pDataSocket->Close();
\n
delete m_pDataSocket;
\n
m_pDataSocket = NULL;
\n
}
\n
if (pThread1 != nullptr)
\n
AfxEndThread(pThread1->m_nThreadID);
\n
if (pThread2 != nullptr)
\n
AfxEndThread(pThread2->m_nThreadID);
\n

\n
// 프로그램 종료
\n
OnOK();;
\n
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
\n
}
\n

\n

\n
int CUDPServerthdDlg::Checksum(Packet* pkt)
\n
{
\n
int checksum = 0;
\n
for (int i = 0; i < strlen(pkt->data); i++) {
\n
checksum += pkt->data[i];
\n
}
\n
checksum = -(checksum);
\n
// TODO: 여기에 구현 코드 추가.
\n
return checksum;
\n
}
\n
\n

\n
클라이언트 부분
\n
\n
#include \"pch.h\"
\n
#include \"framework.h\"
\n
#include \"UDPClientthd.h\"
\n
#include \"UDPClientthdDlg.h\"
\n
#include \"afxdialogex.h\"
\n
#include \"CDataSocket.h\"
\n
CDataSocket* m_pDataSocket;
\n
CString save_message;
\n

\n
CCriticalSection tx_cs;
\n
CCriticalSection rx_cs;
\n

\n
UINT senPort = 17000;
\n
UINT desPort = 19000;
\n
#ifdef _DEBUG
\n
#define new DEBUG_NEW
\n
#endif
\n

\n
// 응용 프로그램 정보에 사용되는 CAboutDlg 대화 상자입니다.
\n
struct ThreadArg;
\n

\n
ThreadArg arg1, arg2;
\n
class CAboutDlg : public CDialogEx
\n
{
\n
public:
\n
CAboutDlg();
\n
// 대화 상자 데이터입니다.
\n
#ifdef AFX_DESIGN_TIME
\n
enum { IDD = IDD_ABOUTBOX };
\n
#endif
\n

\n
protected:
\n
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 지원입니다.
\n

\n
// 구현입니다.
\n
protected:
\n
DECLARE_MESSAGE_MAP()
\n
};
\n

\n
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
\n
{
\n
}
\n

\n
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
\n
{
\n
CDialogEx::DoDataExchange(pDX);
\n
}
\n

\n
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
\n
END_MESSAGE_MAP()
\n

\n

\n
// CUDPClientthdDlg 대화 상자
\n

\n

\n

\n
CUDPClientthdDlg::CUDPClientthdDlg(CWnd* pParent /*=nullptr*/)
\n
: CDialogEx(IDD_UDPCLIENTTHD_DIALOG, pParent)
\n
{
\n
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
\n
}
\n

\n
void CUDPClientthdDlg::DoDataExchange(CDataExchange* pDX)
\n
{
\n
CDialogEx::DoDataExchange(pDX);
\n
DDX_Control(pDX, IDC_EDIT2, m_tx_edit);
\n
DDX_Control(pDX, IDC_EDIT1, m_tx_edit_short);
\n
DDX_Control(pDX, IDC_EDIT3, m_rx_edit);
\n
DDX_Control(pDX, IDC_IPADDRESS1, m_ipaddr);
\n
}
\n

\n
BEGIN_MESSAGE_MAP(CUDPClientthdDlg, CDialogEx)
\n
ON_WM_SYSCOMMAND()
\n
ON_WM_PAINT()
\n
ON_WM_QUERYDRAGICON()
\n
ON_BN_CLICKED(IDC_BUTTON1, &CUDPClientthdDlg::OnBnClickedButton1)
\n
ON_BN_CLICKED(IDC_BUTTON2, &CUDPClientthdDlg::OnBnClickedButton2)
\n
END_MESSAGE_MAP()
\n

\n

\n
// CUDPClientthdDlg 메시지 처리기
\n
UINT TIMERThread(LPVOID run) {
\n
Sleep(3000);
\n
*(bool*)run = FALSE;
\n
return 0;
\n
}
\n

\n
UINT TXThread(LPVOID arg) {
\n
ThreadArg* pArg = (ThreadArg*)arg;
\n
CStringList* pList = pArg->pList;
\n
CUDPClientthdDlg* pDlg = (CUDPClientthdDlg*)pArg->pDlg;
\n
Packet pkt;
\n
CWinThread* pTime;
\n
CList<Packet>* pACK = pArg->pAck;
\n

\n
while (pArg->Thread_run) {
\n
POSITION pos = pList->GetHeadPosition();
\n
POSITION current_pos;
\n
while (pos != NULL) {
\n
current_pos = pos;
\n
tx_cs.Lock();
\n
CString str = pList->GetNext(pos);
\n
tx_cs.Unlock();
\n

\n
CString message;
\n
pDlg->m_tx_edit_short.GetWindowText(message);
\n
message += str + _T(\"\\r\\n\");
\n

\n
pDlg->m_tx_edit.SetWindowTextW(message);
\n
pDlg->m_tx_edit.LineScroll(pDlg->m_tx_edit.GetLineCount());
\n
pDlg->m_tx_edit.SetFocus();
\n
CStringA strA(message);
\n
const char* msg = strA;
\n

\n
char pktMsg[1024];
\n
strncpy_s(pktMsg, msg, sizeof(pktMsg));
\n
for (int i = 0; i < strlen(msg) / 16 + 1; i++) {
\n
memcpy(pkt.data, msg + i * 16, 16);
\n
pkt.sequence = i;
\n
if (i == strlen(msg) / 16)
\n
pkt.max_seq = i;
\n
pkt.checksum = pDlg->Checksum(&pkt);
\n
m_pDataSocket->SendToEx(&pkt, sizeof(Packet), desPort, pDlg->PeerAddr);
\n

\n
int ack_state = 2;
\n
while (ack_state == 2) {
\n
bool run = true;
\n
pTime = AfxBeginThread(TIMERThread,(LPVOID) & run);
\n
while (run == true) {
\n
POSITION pos2 = pACK->GetHeadPosition();
\n
POSITION current_pos2;
\n
while (pos2 != NULL) {
\n
current_pos2 = pos2;
\n
Packet ack = pACK->GetNext(pos2);
\n
ack_state = ack.ack;
\n
run = false;
\n
pACK->RemoveAt(current_pos2);
\n
}
\n
}
\n
if (ack_state == 2)
\n
m_pDataSocket->SendToEx(&pkt, sizeof(Packet), desPort, pDlg->PeerAddr);
\n
}
\n
}
\n
pList->RemoveAt(current_pos);
\n
}
\n
Sleep(10);
\n
}
\n
return 0;
\n
}
\n

\n
UINT RXThread(LPVOID arg) {
\n
ThreadArg* pArg = (ThreadArg*)arg;
\n
CStringList* plist = pArg->pList;
\n
CUDPClientthdDlg* pDlg = (CUDPClientthdDlg*)pArg->pDlg;
\n

\n
while (pArg->Thread_run) {
\n
POSITION pos = plist->GetHeadPosition();
\n
POSITION current_pos;
\n
while (pos != NULL) {
\n
current_pos = pos;
\n
rx_cs.Lock();
\n
CString str = plist->GetNext(pos);
\n
rx_cs.Unlock();
\n

\n
CString message;
\n
pDlg->m_rx_edit.GetWindowText(message);
\n
message += str;
\n
pDlg->m_rx_edit.SetWindowText(message);
\n
pDlg->m_rx_edit.LineScroll(pDlg->m_rx_edit.GetLineCount());
\n
plist->RemoveAt(current_pos);
\n
}
\n
Sleep(10);
\n
}
\n
return 0;
\n
}
\n
BOOL CUDPClientthdDlg::OnInitDialog()
\n
{
\n
CDialogEx::OnInitDialog();
\n

\n
// 시스템 메뉴에 \"정보...\" 메뉴 항목을 추가합니다.
\n

\n
// IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
\n
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
\n
ASSERT(IDM_ABOUTBOX < 0xF000);
\n
\n
CMenu* pSysMenu = GetSystemMenu(FALSE);
\n
if (pSysMenu != nullptr)
\n
{
\n
BOOL bNameValid;
\n
CString strAboutMenu;
\n
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
\n
ASSERT(bNameValid);
\n
if (!strAboutMenu.IsEmpty())
\n
{
\n
pSysMenu->AppendMenu(MF_SEPARATOR);
\n
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
\n
}
\n
}
\n

\n
// 이 대화 상자의 아이콘을 설정합니다.  응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
\n
//  프레임워크가 이 작업을 자동으로 수행합니다.
\n
SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다.
\n
SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다.
\n

\n
// TODO: 여기에 추가 초기화 작업을 추가합니다.
\n
m_ipaddr.SetWindowTextW(_T(\"127.0.0.1\"));
\n

\n
CStringList* newlist = new CStringList;
\n
arg1.pList = newlist;
\n
arg1.Thread_run = 1;
\n
arg1.pDlg = this;
\n

\n
CStringList* newlist2 = new CStringList;
\n
arg2.pList = newlist2;
\n
arg2.Thread_run = 1;
\n
arg2.pDlg = this;
\n

\n
CList<Packet>* pACK = new CList<Packet>;
\n
arg1.pAck = pACK;
\n

\n
WSADATA wsa;
\n
int error_code;
\n
if ((error_code = WSAStartup(MAKEWORD(2, 2), &wsa)) != 0) {
\n
TCHAR buffer[256];
\n
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, 256, NULL);
\n
AfxMessageBox(buffer, MB_ICONERROR);
\n
}
\n
m_pDataSocket = new CDataSocket(this);
\n
m_pDataSocket->Create(senPort, SOCK_DGRAM);
\n
pThread1 = AfxBeginThread(TXThread, (LPVOID)&arg1);
\n
pThread2 = AfxBeginThread(TXThread, (LPVOID)&arg2);
\n
return TRUE;
\n
AfxMessageBox(_T(\"이미 실행 중인 서버가 있습니다.\"), MB_ICONERROR);
\n
return FALSE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
\n
}
\n

\n
void CUDPClientthdDlg::OnSysCommand(UINT nID, LPARAM lParam)
\n
{
\n
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
\n
{
\n
CAboutDlg dlgAbout;
\n
dlgAbout.DoModal();
\n
}
\n
else
\n
{
\n
CDialogEx::OnSysCommand(nID, lParam);
\n
}
\n
}
\n

\n
// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
\n
//  아래 코드가 필요합니다.  문서/뷰 모델을 사용하는 MFC 애플리케이션의 경우에는
\n
//  프레임워크에서 이 작업을 자동으로 수행합니다.
\n

\n
void CUDPClientthdDlg::OnPaint()
\n
{
\n
if (IsIconic())
\n
{
\n
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
\n

\n
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
\n

\n
// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
\n
int cxIcon = GetSystemMetrics(SM_CXICON);
\n
int cyIcon = GetSystemMetrics(SM_CYICON);
\n
CRect rect;
\n
GetClientRect(&rect);
\n
int x = (rect.Width() - cxIcon + 1) / 2;
\n
int y = (rect.Height() - cyIcon + 1) / 2;
\n

\n
// 아이콘을 그립니다.
\n
dc.DrawIcon(x, y, m_hIcon);
\n
}
\n
else
\n
{
\n
CDialogEx::OnPaint();
\n
}
\n
}
\n

\n
// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
\n
//  이 함수를 호출합니다.
\n
HCURSOR CUDPClientthdDlg::OnQueryDragIcon()
\n
{
\n
return static_cast<HCURSOR>(m_hIcon);
\n
}
\n

\n

\n

\n
void CUDPClientthdDlg::ProcessReceive(CDataSocket* pSocket, int nErrorCode)
\n
{
\n
if (pSocket == nullptr)
\n
return;
\n
// TODO: 여기에 구현 코드 추가.
\n
static CString strData;
\n
int nbytes;
\n
Packet pkt;
\n
int datasum = 0;
\n
Packet ack_pkt;
\n
nbytes = pSocket->ReceiveFromEx(&pkt, sizeof(Packet), PeerAddr, desPort);
\n
for (int i = 0; i < strlen(pkt.data); i++) {
\n
datasum += pkt.data[i];
\n
}
\n
char pBuf[17];
\n
memcpy(pBuf, pkt.data, 16);
\n
pBuf[16] = NULL;
\n

\n
if ((pkt.ack == 1) || (pkt.ack == 2)) {
\n
arg1.pAck->AddTail(pkt);
\n
}
\n
else {
\n
if (pkt.sequence != pkt.max_seq) {
\n
if (datasum + pkt.checksum == 0) {
\n
strData += pBuf;
\n
ack_pkt.ack = 1;
\n
ack_pkt.sequence = pkt.sequence;
\n
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
\n
}
\n
else {
\n
ack_pkt.ack = 2;
\n
ack_pkt.sequence = pkt.sequence;
\n
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
\n
}
\n
}
\n
else {
\n
if (datasum + pkt.checksum == 0) {
\n
strData += pBuf;
\n
ack_pkt.ack = 1;
\n
ack_pkt.sequence = pkt.sequence;
\n
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
\n
rx_cs.Lock();
\n
arg2.pList->AddTail((LPCTSTR)strData);
\n
rx_cs.Unlock();
\n
strData = _T(\"\");
\n
}
\n
else {
\n
ack_pkt.ack = 2;
\n
ack_pkt.sequence = pkt.sequence;
\n
pSocket->SendToEx(&ack_pkt, sizeof(Packet), desPort, PeerAddr);
\n
}
\n
}
\n
}
\n
\n
}
\n

\n

\n
void CUDPClientthdDlg::ProcessClose(CDataSocket* pSocket, int nErrorCode)
\n
{
\n
if (pSocket == nullptr)
\n
return;
\n
// TODO: 여기에 구현 코드 추가.
\n
pSocket->Close();
\n
delete m_pDataSocket;
\n
m_pDataSocket = nullptr;
\n
int len = m_rx_edit.GetWindowTextLengthW();
\n
CString tx_Message = _T(\"##접속종료##\\r\\n\");
\n
m_rx_edit.SetSel(len, len);
\n
m_rx_edit.ReplaceSel(tx_Message);
\n
}
\n

\n

\n
void CUDPClientthdDlg::OnBnClickedButton1()
\n
{
\n
CString tx_message;
\n
m_tx_edit_short.GetWindowText(tx_message);
\n
send_message += tx_message + _T(\"\\r\\n\");
\n

\n
tx_cs.Lock();
\n
arg1.pList->AddTail(tx_message);
\n
tx_cs.Unlock();
\n

\n
m_tx_edit_short.SetWindowTextW(_T(\"\"));
\n
m_tx_edit.SetWindowTextW(send_message);
\n
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
\n
}
\n

\n

\n
void CUDPClientthdDlg::OnBnClickedButton2()
\n
{
\n
if (m_pDataSocket == NULL) {
\n
AfxMessageBox(_T(\"이미 접속 종료\"));
\n
}
\n
else {
\n
arg1.Thread_run = 0;
\n
arg2.Thread_run = 2;
\n
m_pDataSocket->Close();
\n
delete m_pDataSocket;
\n
m_pDataSocket = nullptr;
\n
}
\n
if (pThread1 != nullptr)
\n
AfxEndThread(pThread1->m_nThreadID);
\n
if (pThread2 != nullptr)
\n
AfxEndThread(pThread2->m_nThreadID);
\n

\n
// 프로그램 종료
\n
OnOK();
\n
}
\n

\n
int CUDPClientthdDlg::Checksum(Packet* pkt)
\n
{
\n
int checksum = 0;
\n
for (int i = 0; i < strlen(pkt->data); i++) {
\n
checksum += pkt->data[i];
\n
}
\n
checksum = -(checksum);
\n
// TODO: 여기에 구현 코드 추가.
\n
return checksum;
\n
}
\n
\n
서버의 헤더부분
\n
\n
#include \"afxcoll.h\"
\n
#include \"afxwin.h\"
\n
#pragma once
\n
struct Packet {
\n
int checksum;
\n
int max_seq;
\n
int ack;
\n
int sequence;
\n
char data[1024];
\n
// 필요한 필드들을 추가할 수 있습니다.
\n
};
\n
struct ThreadArg {
\n
CStringList* pList;
\n
CDialogEx* pDlg;
\n
CList<Packet>* pAck;
\n
BOOL Thread_run;
\n
};
\n

\n
class CDataSocket;
\n

\n
// CUDPServerthdDlg 대화 상자
\n
class CUDPServerthdDlg : public CDialogEx
\n
{
\n
// 생성입니다.
\n
public:
\n
CUDPServerthdDlg(CWnd* pParent = nullptr); // 표준 생성자입니다.
\n
// 대화 상자 데이터입니다.
\n
#ifdef AFX_DESIGN_TIME
\n
enum { IDD = IDD_UDPSERVERTHD_DIALOG };
\n
#endif
\n
\n
protected:
\n
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.
\n
// 구현입니다.
\n
protected:
\n
HICON m_hIcon;
\n
// 생성된 메시지 맵 함수
\n
virtual BOOL OnInitDialog();
\n
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
\n
afx_msg void OnPaint();
\n
afx_msg HCURSOR OnQueryDragIcon();
\n
DECLARE_MESSAGE_MAP()
\n
public:
\n
CWinThread* pThread1, * pThread2;
\n
ThreadArg arg1, arg2;
\n
CDataSocket* m_pDataSocket;
\n
CString PeerAddr;
\n
CString send_message;;
\n
CEdit m_tx_edit_short;
\n
CEdit m_tx_edit;
\n
CEdit m_rx_edit;
\n
void ProcessReceive(CDataSocket* pSocket, int nErrorCode);
\n
void ProcessClose(CDataSocket* pSocket, int nErrorCode);
\n
afx_msg void OnBnClickedButton1();
\n
afx_msg void OnBnClickedButton2();
\n
int Checksum(Packet* pkt);
\n
};
\n
\n
클라이언의 헤더 부분
\n
\n
#pragma once
\n
#include \"afxcoll.h\"
\n
#include \"afxwin.h\"
\n
struct Packet {
\n
int checksum;
\n
int max_seq;
\n
int ack;
\n
int sequence;
\n
char data[1024];
\n
// 필요한 필드들을 추가할 수 있습니다.
\n
};
\n
struct ThreadArg {
\n
CStringList* pList;
\n
CDialogEx* pDlg;
\n
CList<Packet>* pAck;
\n
BOOL Thread_run;
\n
};
\n
class CDataSocket;
\n

\n
// CUDPClientthdDlg 대화 상자
\n
class CUDPClientthdDlg : public CDialogEx
\n
{
\n
// 생성입니다.
\n
public:
\n
CUDPClientthdDlg(CWnd* pParent = nullptr); // 표준 생성자입니다.
\n
// 대화 상자 데이터입니다.
\n
#ifdef AFX_DESIGN_TIME
\n
enum { IDD = IDD_UDPCLIENTTHD_DIALOG };
\n
#endif
\n

\n
protected:
\n
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.
\n
// 구현입니다.
\n
protected:
\n
HICON m_hIcon;
\n
// 생성된 메시지 맵 함수
\n
virtual BOOL OnInitDialog();
\n
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
\n
afx_msg void OnPaint();
\n
afx_msg HCURSOR OnQueryDragIcon();
\n
DECLARE_MESSAGE_MAP()
\n
public:
\n
CWinThread* pThread1, * pThread2;
\n
ThreadArg arg1, arg2;
\n
CString PeerAddr;
\n
CString send_message;
\n
CEdit m_tx_edit;
\n
CEdit m_tx_edit_short;
\n
CEdit m_rx_edit;
\n
void ProcessReceive(CDataSocket* pSocket, int nErrorCode);
\n
void ProcessClose(CDataSocket* pSocket, int nErrorCode);
\n
afx_msg void OnBnClickedButton1();
\n
afx_msg void OnBnClickedButton2();
\n
CIPAddressCtrl m_ipaddr;
\n
int Checksum(Packet* pkt);
\n
};
\n
\n
클라이언트의 헤더 부분
\n

\n
\n
', '1_10405_447254292', ' 현재 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); }; 클라이언트의 헤더 부분 ', 'https://cboard.net/sitemap/og_image.php?text=mfc기반 udp통신 오류&link=https://cboard.net/k/1_10405_447254292', '2023.06.04')
Data too long for column 'content' at row 1 mfc기반 udp통신 오류

mfc기반 udp통신 오류

mfc기반 udp통신 오류

작성일 2023.06.04댓글 1건
    게시물 수정 , 삭제는 로그인 필요

현재 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);
};
클라이언트의 헤더 부분




profile_image 익명 작성일 -

주어진 코드를 살펴보니 UDP 통신을 구현하기 위해 MFC를 사용한 서버와 클라이언트 프로그램이 포함되어 있습니다. 주어진 코드에서 발견된 몇 가지 문제와 수정해야 할 부분을 설명하겠습니다.

1. 서버 부분

- `OnOK()` 함수에서 두 번의 반환문이 있습니다. 두 번째 반환문은 실행되지 않으므로, 첫 번째 반환문 아래에 있는 코드들은 실행되지 않습니다.

- `OnInitDialog()` 함수에서 "이미 실행 중인 서버가 있습니다."와 같은 메시지를 표시한 뒤에도 `return TRUE;` 구문이 실행되어, 대화 상자가 초기화되고 계속 실행됩니다. `return FALSE;` 구문을 추가하여 초기화를 중단하고 함수를 종료해야 합니다.

- `ProcessClose()` 함수에서 서버 소켓을 닫은 뒤에 `delete m_pDataSocket;` 구문이 실행되는데, 이전에 이미 소켓을 닫았기 때문에 소켓을 삭제하는 구문은 필요하지 않습니다.

2. 클라이언트 부분

- `OnInitDialog()` 함수에서 "이미 실행 중인 서버가 있습니다."와 같은 메시지를 표시한 뒤에도 `return TRUE;` 구문이 실행되어, 대화 상자가 초기화되고 계속 실행됩니다. `return FALSE;` 구문을 추가하여 초기화를 중단하고 함수를 종료해야 합니다.

- `ProcessClose()` 함수에서 클라이언트 소켓을 닫은 뒤에 `delete m_pDataSocket;` 구문이 실행되는데, 이전에 이미 소켓을 닫았기 때문에 소켓을 삭제하는 구문은 필요하지 않습니다.

3. 공통 부분

- `Checksum()` 함수에서 체크섬 계산을 위해 `strlen(pkt->data)`를 사용하고 있습니다. 하지만 UDP 패킷은 고정된 크기인 1024바이트를 가지므로, `strlen(pkt->data)` 대신 1024를 사용해야 합니다.

이외에도 체크섬과 ARQ (Automatic Repeat Request)를 구현하려는 의도가 보이지만, 주어진 코드에서 해당 기능이 완전하게 구현되지 않았습니다. ARQ와 체크섬을 구현하는 방법은 복잡하므로, 자세한 내용은 추가 정보가 필요합니다.

위의 수정된 코드를 참고하여 문제를 해결하고 UDP 통신이 정상적으로 동작하도록 코드를 수정해보시기 바랍니다.

제가 써본 챗gpt 어플 중에서 제일 괜찮은거 하나 알려드릴게요.

무료에 로그인도 필요없어서 제가 요즘 제일 많이 쓰는 어플인데 HaeDab이라는 앱이에요.

https://apps.apple.com/kr/app/haedab/id1672179251

MFC socket 사용 (UDP)

... UDP는 비접속기반입니다. 데이터를 통신할 때, 불특정 다수에게서 통신을 받을 수 있습니다. 통신은 정해진 포트를 통해서 이루어집니다....

tcp udp

... 즉, 프로세스 대 프로세스 데이터 전달과 오류... - 통신 시작 : 3 way handshake, 통신 종료 : 4 way handshake TCP... UDP기반의 네트워크 프로그램은 네트워크 연결이라는...

[c++]시리얼 통신 관련

... 비주얼 c++기반인 시리얼 통신을... // Call this when using MFC in a shared DLL #else... 이를 TRUE로 하면 패리티 검 사가 수행되고 오류가...

Ip와 http사이의 전환

... TCP/IP 기반의 소켓 통신을 이용하자. 통신 프로토콜... 통신 프로토콜은 신호 체계, 오류 감지 및 수정... TCP와 UDP를 사용. 80번 포트 사용. 한마디로...

윈도우 XP의 RPC오류에 대해서...

... 질문이에요 윈도우 XP의 RPC오류에 대해서 알고 싶습니다... 통신[IPC]메커니즘을 구현 할 수 있습니다 이프로토콜은 원래 OSF[Open Software Foundation]RPC 프로터콜을 기반으로...