老师的作业,让做一个局域网聊天室!看了孙鑫的视频!自己也简单的实现了一下!感觉挺棒的!
一个中心-----"练习"
下面贴出自己的简单理解,告诉自动掠过,,,,,,,,,
聊天室基于UDP协议,
1.套接字初始化
AfxSocketInit()函数初始化
1 if(!AfxSocketInit())
2 {
3 AfxMessageBox("加载套接字失败库!");
4 return FALSE;
5 }
套接字初始化完成,当然我们得在预编译头文件里面将AfxSocketInit()所需的头文件包含进来,否则他不认识的!
1 #include <afxsock.h> //stdfax.h中的
BOOL CNetworkDlg::InintScoket() { m_scoket=socket(AF_INET,SOCK_DGRAM,0); //自己要做的工作-----定义私有变量成员 if(INVALID_SOCKET==m_scoket) { MessageBox("套接字创建失败"); return FALSE; } SOCKADDR_IN addrSock; addrSock.sin_family=AF_INET; addrSock.sin_port=htons(6000); addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY) ; int reval; reval=bind(m_scoket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR)); if(SOCKET_ERROR==reval) { closesocket(m_scoket); MessageBox("绑定失败!"); return FALSE; } return TRUE; }
这样我们就可以在OnInitDialog()里面调用了;
2.接收端
接收端由于要处理实时消息,所以单独做出一个线程来处理!我们来看一下MSDN的解释:
CreateThread The CreateThread function creates a thread to execute within the virtual address space of the calling process. To create a thread that runs in the virtual address space of another process, use the CreateRemoteThread function. HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD DWORD dwStackSize, // initial stack size LPTHREAD_START_ROUTINE lpStartAddress, // thread function LPVOID lpParameter, // thread argument DWORD dwCreationFlags, // creation option LPDWORD lpThreadId // thread identifier );
以上函数,各个参数我就这里不解释了(具体我其实不知道看孙鑫十五课)第三个参数是我们关注的对象!只能传进去一个参数!然而我们想处理的却有两个:套接字和窗口句柄!
我们注意到这是一个指针!所以我们做一个结构体将其作为指针传进得到两个值
1 struct RECEPARAM
2 {
3 SOCKET socket;
4 HWND hwnd;
5 };
然后放到OnInitDialog()调用CreateThread()得到其句柄
1 RECEPARAM *pReceParam=new RECEPARAM;
2 pReceParam->socket=m_scoket;
3 pReceParam->hwnd=m_hWnd;
4 HANDLE hThread=CreateThread(NULL,0,ReceProc,(LPVOID)pReceParam,0,NULL); //注意到Rece是线程创建的函数!
5 CloseHandle(hThread);
下面写先从创建函数!ReceProc();
1 DWORD WINAPI CNetworkDlg::ReceProc(LPVOID lpParameter)
2 {
3 SOCKET sock=((RECEPARAM*)lpParameter)->socket;
4 HWND hwnd=((RECEPARAM*)lpParameter)->hwnd;
5
6 //接收数据
7 SOCKADDR_IN addr_form;
8 int len=sizeof(SOCKADDR);
9 char recBuf[200];
10 char tempBuf[300];
11
12 int retval;
13 while(TRUE)
14 {
15 retval=recvfrom(sock,recBuf,200,0,(SOCKADDR*)&addr_form,&len);
16 if ( SOCKET_ERROR ==retval)
17 {
18 break;
19 }
20 sprintf(tempBuf,"%s 说: %s",inet_ntoa(addr_form.sin_addr),recBuf);
21 ::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);
22 }
23
24
25 return 0;
26 }
整个程序运行起来,线程就不断的跑了(while(true))!
当来消息时,怎么办呢?
下面是消息处理函数:
1 afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam); //声明为私有函数
1 void CNetworkDlg::OnRecvData(WPARAM wParam,LPARAM lParam)
2 {
3
4 CString str=(char*)lParam;
5 CString strTemp;
6 GetDlgItemText(IDC_EDIT_RECE,strTemp);
7 str+="\r\n";
8 str+=strTemp;
9 SetDlgItemText(IDC_EDIT_RECE,str);
10 }
这样就能处理了.......
下面类看一下界面吧(开始就该设计好的)
当要点击发送时要完成的工作:获取IP,保存并传入内容,送过去让线程捕获!
双击界面“发送”
1 void CNetworkDlg::OnBtnSend()
2 {
3 // TODO: Add your control notification handler code here
4 DWORD dwip;
5
6 ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS2))->GetAddress(dwip);
7 SOCKADDR_IN addrTo;
8 addrTo.sin_family=AF_INET;
9 addrTo.sin_port=htons(6000);
10 addrTo.sin_addr.S_un.S_addr=htonl(dwip) ;
11
12 CString strSend;
13 GetDlgItemText(IDC_EDIT2,strSend);
14 sendto(m_scoket,strSend,strSend.GetLength()+1,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR));
15 SetDlgItemText(IDC_EDIT2,"");
16
17 }
好了,发送过去了,正在跑动的线程一捕获,立马显示给编辑框!
我实验了一下,有个bug,看不到自己的发送内容(明明保存了内容怎么就消失了呢?)
自己给自己发可以,两台电脑上有问题!摸索中,,,,,,,,