基于UDP的网络聊天程序
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
创建一个MFC的对话框工程Chat,界面如图
下面是实现步骤:
一、调用Afxstock全局函数初始化套接字库,在CChatApp::InitInstance()中添加代码:
if (!AfxSocketInit())
{
AfxMessageBox("加载字库失败!");
return FALSE;
}
二、在CChatDlg类中添加一个成员函数:stocketInit(),并在CChatDlg::OnInitDialog()中调用一下,代码如下:
BOOL CChatDlg::stocketInit()
{
m_socket=socket(AF_INET,SOCK_DGRAM,0);
if (INVALID_SOCKET==m_socket)
{
MessageBox("创建套接字失败!");
return FALSE;
}
SOCKADDR_IN socket_in;
socket_in.sin_family=AF_INET;
socket_in.sin_port=htons(3000);
socket_in.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
int retval;
retval=bind(m_socket,(SOCKADDR*)&socket_in,sizeof(SOCKADDR));
if (SOCKET_ERROR==retval)
{
closesocket(m_socket);
MessageBox("绑定套接字失败!");
return FALSE;
}
return TRUE;
}
三、在CChatDlg::OnInitDialog()中创建一个线程,用于接收数据。这是本程序的关键一步,
1、接收数据的recvfrom函数会一直等待数据的到来,如果放在主线程中会赌塞系统,所以必须在建一个线程实现。
2、线程必须接收对话框传来的套接字,用来接收数据,而得到的数据必须回传给对话框显示出来,但是线程只能接收一个LPVOID型的参数,要同时接受2个参数,就需要提前定义一个struct,里面包含2个成员:sock和hwnd,把这个结构的指针做为参数传递给线程。
3、数据的回传通过自定义消息实现,把接收到的数据作为消息的附件参数传给对话框。
创建线程的代码:
BOOL CChatDlg::OnInitDialog()
{ ............
RECVPARAM* pRecvparam=new RECVPARAM; //RECVPARAM是含2个参数的结构体
pRecvparam->socket=m_socket;
pRecvparam->hwnd=m_hWnd;
HANDLE
hThead=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvparam,0,NULL);
CloseHandle(hThead);
...............
}
线程代码:
DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter)
{
SOCKET sock;
HWND hwnd;
sock=((RECVPARAM*)lpParameter)->socket; //先取出2个参数
hwnd=((RECVPARAM*)lpParameter)->hwnd;
delete lpParameter;
SOCKADDR_IN addrFrom;
int len=sizeof(SOCKADDR);
//AfxMessageBox("线程启动");
char recvBuf[200];
char tempBuf[300];
int revale;
while (TRUE)
{
revale=recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,&len); //接收数据
if (SOCKET_ERROR==revale)
break;
sprintf(tempBuf,"%s 说:%s",inet_ntoa(addrFrom.sin_addr),recvBuf);
::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf); //给对话框发消息,传递接收的数据
//AfxMessageBox(tempBuf);
}
return TRUE;
}
四、对话框中加一个对消息的响应函数。需要在3个地方加代码:函数原型说明、消息映射、函数代码。
void CChatDlg::OnRecvData(WPARAM wParam,LPARAM lParam)
{
CString strRecv=(char*)lParam;
CString strTemp;
GetDlgItemText(IDC_EDIT_RECV,strTemp);
strTemp+="\r\n";
strTemp+=strRecv;
SetDlgItemText(IDC_EDIT_RECV,strTemp);
}
五、接收部分完成,设计发送部分,给“发送”按钮增加一个响应函数
void CChatDlg::OnButtonSend()
{
// TODO: Add your control notification handler code here
DWORD dwIp;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->GetAddress(dwIp);
SOCKADDR_IN addrTo;
addrTo.sin_family=AF_INET;
addrTo.sin_addr.S_un.S_addr=htonl(dwIp);
addrTo.sin_port=htons(3000);
CString strSend;
GetDlgItemText(IDC_EDIT_SEND,strSend);
sendto(m_socket,strSend,strSend.GetLength()+1,0,(SOCKADDR*)&addrTo,sizeof(SOCK ADDR));
SetDlgItemText(IDC_EDIT_SEND,"");
//char strS[200];
//strS=strSend.Left(strSend.GetLength());
}
总结体会和存在的问题:
函数参数的传递非常巧妙;自定义消息的响应可以当中断使用;对话框控件的使用非常灵活。