扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
说明
锁定模式下为了避免socket在进行IO操作时一直处于“凝固”状态,简单地用两个线程来实现:一个线程用于数据的接收;另一个线程则用于对接收到的数据进行相关的处理。因为由两个线程来实现,其特点:
<!--[if !supportLists]-->① <!--[endif]-->对数据的处理可以是耗时操作,它不会对数据的接收带来影响。
<!--[if !supportLists]-->② <!--[endif]-->对数据的接收与处理分别在不同的线程内,故应考虑数据的完整性,应避免在数据接收完全之前就对数据进行操作,可以以多种方式实现:如Mutex,Semphore,CriticalSection等同步技术。
<!--[if !supportLists]-->③ <!--[endif]-->当数据接收完全之后,还需要及时的通知另一个线程,以便及时处理。其实现方法是:当接收完数据后,发送已完成信号。
详细说明参见<Windows网络编程>一书。
本代码中应用CriticalSection和event来实现。
需要注意的是:event为自动重置。
完整代码及注释
// zBlogSocket.cpp : 定义控制台应用程序的入口点。 // //多线程socket锁定 <!--[if !supportEmptyParas]--> <!--[endif]--> #include "stdafx.h" #include <WinSock2.h> #include <Windows.h> #include <iostream> using namespace std; <!--[if !supportEmptyParas]--> <!--[endif]--> CRITICAL_SECTION cs; HANDLE hComplete; TCHAR buf[BUFSIZ]; int nBytes; //number of per receive const int nNumPerRecv = BUFSIZ; <!--[if !supportEmptyParas]--> <!--[endif]--> //从socket接收数据线程 DWORD WINAPI ReadThread(LPVOID lpParam); //对接受到的数据进行计算的线程 DWORD WINAPI ComptThread(LPVOID lpParam); <!--[if !supportEmptyParas]--> <!--[endif]--> int _tmain(int argc, _TCHAR* argv[]) { WSAData wsd; int nRet = WSAStartup(0x0202,&wsd); if (nRet != 0) { cout << "WSAStartup Error = " << WSAGetLastError() << endl; return 1; } <!--[if !supportEmptyParas]--> <!--[endif]--> SOCKET soRecv = socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN siRecv; siRecv.sin_addr.s_addr = inet_addr("127.0.0.1"); siRecv.sin_family = AF_INET; siRecv.sin_port = htons(5150); <!--[if !supportEmptyParas]--> <!--[endif]--> nRet = bind(soRecv,(struct sockaddr*)&siRecv,sizeof(siRecv)); if (nRet == SOCKET_ERROR) { cout << "bind Error = " << WSAGetLastError() << endl; return 1; } <!--[if !supportEmptyParas]--> <!--[endif]--> listen(soRecv,8); <!--[if !supportEmptyParas]--> <!--[endif]--> <!--[if !supportEmptyParas]--> <!--[endif]--> HANDLE hThreads[2]; DWORD dwThread[2]; <!--[if !supportEmptyParas]--> <!--[endif]--> //初始化cs InitializeCriticalSection(&cs); <!--[if !supportEmptyParas]--> <!--[endif]--> hThreads[0] = CreateThread(NULL,0,ReadThread,(LPVOID)soRecv,0,&dwThread[0]); hThreads[1] = CreateThread(NULL,0,ComptThread,NULL,0,&dwThread[1]);
//创建自动重置的event对象,当ReadThread接收数据完毕 //后将信号置为signaled hComplete = CreateEvent(NULL,false,FALSE,"evt");
//等待创建的两个线程结束 WaitForMultipleObjects(2,hThreads,true,INFINITE); <!--[if !supportEmptyParas]--> <!--[endif]--> //清除cs DeleteCriticalSection(&cs); <!--[if !supportEmptyParas]--> <!--[endif]--> return 0; } <!--[if !supportEmptyParas]--> <!--[endif]--> //从socket接收数据线程 DWORD WINAPI ReadThread(LPVOID lpParam){ int nTotal = 0; int nRead = 0; int nLeft = 0; int nReadBytes = 0; int nBytes = 0; SOCKET pSoRecv = (SOCKET)lpParam; int dwSend; SOCKADDR_IN siSend; SOCKET soAccept; <!--[if !supportEmptyParas]--> <!--[endif]--> <!--[if !supportEmptyParas]--> <!--[endif]--> while (1) { <!--[if !supportEmptyParas]--> <!--[endif]--> nTotal = 0; nLeft = nNumPerRecv; <!--[if !supportEmptyParas]--> <!--[endif]--> /* 10014错误原因 * int dwSend = sizeof(dwSend); Error = 10014 */ int dwSend = sizeof(siSend); soAccept = accept(pSoRecv,(struct sockaddr*)&siSend,&dwSend); if (soAccept == SOCKET_ERROR) { cout << "accept Error = " << WSAGetLastError() << endl; system("pause"); <!--[if !supportEmptyParas]--> <!--[endif]--> } <!--[if !supportEmptyParas]--> <!--[endif]--> <!--[if !supportEmptyParas]--> <!--[endif]--> //接收到的数据为空 nBytes = 0; memset(buf,0,BUFSIZ); while (nTotal != nNumPerRecv) { //同步操作进入cs EnterCriticalSection(&cs); /* * Recv data from socket and place data in buf[nBytes] */ //nRead = recv(soAccept,&buf[BUFSIZ - nBytes],nLeft,0); nRead = recv(soAccept,&buf[nBytes],nLeft,0); if (nRead == -1) { cout << "recv error = " << WSAGetLastError() << endl; ExitThread(1); } nTotal += nRead; nLeft -= nRead; nBytes += nRead; //离开cs LeaveCriticalSection(&cs); <!--[if !supportEmptyParas]--> <!--[endif]--> } //激发event SetEvent(hComplete); } } //对接受到的数据进行计算的线程 DWORD WINAPI ComptThread(LPVOID lpParam){ //等待ReadThread将数据接受完成后再进行计算 while (1) { WaitForSingleObject(hComplete,INFINITE); <!--[if !supportEmptyParas]--> <!--[endif]--> //对全局变量操作进入cs EnterCriticalSection(&cs); cout << buf << endl; nBytes -= nNumPerRecv; //离开cs LeaveCriticalSection(&cs); } <!--[if !supportEmptyParas]--> <!--[endif]--> return 0; <!--[if !supportEmptyParas]--> <!--[endif]--> } |
<!--[if !supportEmptyParas]--> <!--[endif]-->
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者