泉州建设网站公司吗,网络运维工程师自学,小程序跳转wordpress,网站建设公司有多少写在前面
此前的回声服务器/客户端都是在主线程中阻塞交互#xff0c;本文将使用多线程方式实现服务器/客户端。
互斥量相关接口
使用多线程#xff0c;自然避免不了线程同步问题。
因本文使用互斥量实现线程同步#xff0c;因此仅介绍互斥量相关接口#xff0c;其他实…写在前面
此前的回声服务器/客户端都是在主线程中阻塞交互本文将使用多线程方式实现服务器/客户端。
互斥量相关接口
使用多线程自然避免不了线程同步问题。
因本文使用互斥量实现线程同步因此仅介绍互斥量相关接口其他实现线程同步的方式如关键代码段、事件以及信号量等可自行查阅MSDN帮助文档。
创建互斥量
使用CreateMutex创建互斥量原型如下
#include windows.h
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);
成功时返回创建的互斥量对象句柄失败返回NULL lpMutexAttributes传递安全相关的配置信息使用默认安全设置时可以传递NULL bInitialOwner如果为TRUE则创建出的互斥量对象属于调用该函数的线程同时进入non-signaled状态 如果为FALSE则创建出的互斥量对象不属于任何线程此时状态为signaled lpName: 用于命名互斥量对象。传入NULL时创建无名的互斥量对象。
销毁互斥量
互斥量属于系统内核资源使用完后需要手动释放。使用CloseHandle函数释放互斥量资源原型如下
BOOL CloseHandle(HANDLE hObject);成功时返回TRUE失败时返回FALSE hObject 要销毁的内核对象的句柄
获取互斥量
通过WaitForSingleObject接口获取互斥量原型如下
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);hHandle对象的句柄。 如果等待仍在等待时关闭此句柄则函数的行为未定义。 dwMilliseconds超时间隔以毫秒为单位。 如果指定了非零值该函数将等待对象发出信号或间隔。 如果 dwMilliseconds 为零则如果对象未发出信号则函数不会输入等待状态;它始终会立即返回。 如果 dwMilliseconds 为 INFINITE则仅当发出对象信号时该函数才会返回。
释放互斥量
使用ReleaseMutex释放互斥量使其转变为signaled状态。
BOOL ReleaseMutex(HANDLE hMutex);成功时返回TRUE失败时返回FALSE hMutex: 需要释放解除拥有的互斥量对象句柄
多线程服务器
多线程服务器使用一个全局的socket数组维护连接的客户端socket在主线程中等待客户端的连接每有一个客户端连接时就单独开启一个线程提供回声服务使用一个全局的互斥量对象实现各提供回声服务线程的线程同步。
代码如下
// MultiThread_Server.cpp : 定义控制台应用程序的入口点。
//#include stdafx.h
#include process.h
#include WinSock2.h
#include string
#pragma comment(lib, ws2_32.lib)using namespace std;#define BUF_SIZE 100
#define MAX_CLNT 256unsigned WINAPI HandleClnt(void* arg);
void SendMsg(char* arg, int len);HANDLE hMutex;
int clntCnt 0;
SOCKET clntSocks[MAX_CLNT];void WriteRunLog(LPCSTR lpszLog, int len);int _tmain(int argc, _TCHAR* argv[])
{if (argc ! 2){printf(argc error!\n);return -1;}WSADATA wsaData;if (0 ! WSAStartup(MAKEWORD(2, 2), wsaData)){printf(WSAStartup error!\n);return -1;}SOCKET srvSock socket(PF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET srvSock){printf(socket error!\n);WSACleanup();return -1;}SOCKADDR_IN srvAddr;memset(srvAddr, 0, sizeof(srvAddr));srvAddr.sin_family PF_INET;srvAddr.sin_addr.s_addr htonl(ADDR_ANY);srvAddr.sin_port htons(_ttoi(argv[1]));if (SOCKET_ERROR bind(srvSock, (sockaddr*)srvAddr, sizeof(srvAddr))){printf(bind error!\n);closesocket(srvSock);WSACleanup();return -1;}if (SOCKET_ERROR listen(srvSock, 5)){printf(listen error!\n);closesocket(srvSock);WSACleanup();return -1;}SOCKADDR_IN cltAddr;memset(cltAddr, 0, sizeof(cltAddr));int nCltAddrSize sizeof(cltAddr);hMutex CreateMutex(NULL, FALSE, NULL);while (true){//接受连接线程nCltAddrSize sizeof(cltAddr);puts(wait for client connect...);SOCKET cltSock accept(srvSock, (sockaddr*)cltAddr, nCltAddrSize);if (cltSock INVALID_SOCKET){printf(accept error\n);continue;}//等待操作互斥量数组WaitForSingleObject(hMutex, INFINITE);clntSocks[clntCnt] cltSock;ReleaseMutex(hMutex);//最后开启该套接字的消息处理线程HANDLE hThread (HANDLE)_beginthreadex(NULL, 0, HandleClnt, (void*)cltSock, 0, NULL);printf(Connected Client IP: %s \n, inet_ntoa(cltAddr.sin_addr));}CloseHandle(hMutex);closesocket(srvSock);WSACleanup();puts(main thread end.);puts(任意键继续...);getchar();return 0;
}unsigned WINAPI HandleClnt(void* arg)
{SOCKET cltSock *((SOCKET*)arg);int nRecvLen 0;char Msg[BUF_SIZE] {};char Log[2*BUF_SIZE] {};while ( (nRecvLen recv(cltSock, Msg, BUF_SIZE, 0)) ! 0 ){Msg[nRecvLen] 0;//sprintf(Log, recv msg from client《%d》: %s\n, cltSock, Msg);//WriteRunLog(Log, strlen(Log));SendMsg(Msg, nRecvLen);}//若客户端断开连接则在套接字数组中清除对应socketWaitForSingleObject(hMutex, INFINITE);//找到要清除的套接字从该位置开始后续元素前移覆盖删除//双指针实现覆盖删除int slow 0;int fast 0;for (; fast clntCnt; fast){if (clntSocks[fast] cltSock){continue;}clntSocks[slow] clntSocks[fast];}clntSocks[slow] INVALID_SOCKET;clntCnt--;ReleaseMutex(hMutex);closesocket(cltSock);//sprintf(Log, Client %d Disconnected...\n, cltSock);//WriteRunLog(Log, strlen(Log));return 0;}void SendMsg(char* arg, int len)
{//回复所有客户端WaitForSingleObject(hMutex, INFINITE);char Log[2*BUF_SIZE] {};for (int i 0; i clntCnt; i){//sprintf(Log, Send to client 《%d》 msg: %s\n, clntSocks[i], len);//WriteRunLog(Log, strlen(Log));send(clntSocks[i], arg, len, 0);}ReleaseMutex(hMutex);
}多线程客户端
此前的回声客户端均在主线程中进行读写操作在多线程客户端中使用两个线程分别处理读写操作。
代码如下
// MultiThread_Client.cpp : 定义控制台应用程序的入口点。
//#include stdafx.h
#include process.h
#include WinSock2.h
#pragma comment(lib, ws2_32.lib)#define BUF_SIZE 100
#define NAME_SIZE 20unsigned WINAPI SendMsg(void* arg);
unsigned WINAPI RecvMsg(void* arg);char name[NAME_SIZE] [DEFAULT];
char msg[BUF_SIZE] {};int _tmain(int argc, _TCHAR* argv[])
{if (argc ! 4){printf(argc error!\n);return -1;}WSADATA wsaData;if (0 ! WSAStartup(MAKEWORD(2, 2), wsaData)){printf(WSAStartup error!\n);return -1;}printf(server ip: %s, port: %s, client name: %s\n, argv[1], argv[2], argv[3]);sprintf(name, [%s], argv[3]);SOCKET cltSock socket(PF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET cltSock){puts(socket error!);WSACleanup();return -1;}SOCKADDR_IN srvAddr;memset(srvAddr, 0, sizeof(srvAddr));srvAddr.sin_family PF_INET;srvAddr.sin_addr.s_addr inet_addr(argv[1]);srvAddr.sin_port htons(_ttoi(argv[2]));if (connect(cltSock, (sockaddr*)srvAddr, sizeof(srvAddr)) SOCKET_ERROR){puts(connect error!);closesocket(cltSock);WSACleanup();return -1;}//开启客户端的接收和发送线程HANDLE hSendThread (HANDLE)_beginthreadex(NULL, 0, SendMsg, (void*)cltSock, 0, NULL);HANDLE hRecvThread (HANDLE)_beginthreadex(NULL, 0, RecvMsg, (void*)cltSock, 0, NULL);WaitForSingleObject(hSendThread, INFINITE);WaitForSingleObject(hRecvThread, INFINITE);closesocket(cltSock);WSACleanup();puts(任意键继续...);getchar();return 0;
}unsigned WINAPI SendMsg(void* arg)
{SOCKET cltSock *((SOCKET*)arg);char nameMsg[NAME_SIZE BUF_SIZE] {};while (true){//printf(Input Msg: );fgets(msg, BUF_SIZE, stdin);if ( !strcmp(msg, q\n) || !strcmp(msg, Q\n) ){puts(Disconnect...);break;}sprintf(nameMsg, %s %s, name, msg);send(cltSock, nameMsg, strlen(nameMsg), 0);}//exit(0);closesocket(cltSock);printf(client %d thread end.\n, cltSock);return 0;
}unsigned WINAPI RecvMsg(void* arg)
{SOCKET cltSock *((SOCKET*)arg);char nameMsg[NAME_SIZE BUF_SIZE] {};int nRecvLen 0;while (true){nRecvLen recv(cltSock, nameMsg, NAME_SIZE BUF_SIZE - 1, 0);if (nRecvLen -1){puts(server disconnected!);return -1;}nameMsg[nRecvLen] 0;printf(nameMsg from server: %s\n, nameMsg);}return 0;
}运行结果如下
总结
虽然使用互斥量实现了简单的多线程服务器/客户端但也只是借此熟悉下线程及线程同步相关的接口可以明显的看到效率还是比较低下的。
要想使用高效的Windows服务器客户端可以使用IOCP完成端口实现。 文章转载自: http://www.morning.wkkqw.cn.gov.cn.wkkqw.cn http://www.morning.xknsn.cn.gov.cn.xknsn.cn http://www.morning.mtrrf.cn.gov.cn.mtrrf.cn http://www.morning.rfpb.cn.gov.cn.rfpb.cn http://www.morning.hyjpl.cn.gov.cn.hyjpl.cn http://www.morning.qrwdg.cn.gov.cn.qrwdg.cn http://www.morning.tfpbm.cn.gov.cn.tfpbm.cn http://www.morning.jokesm.com.gov.cn.jokesm.com http://www.morning.ndcjq.cn.gov.cn.ndcjq.cn http://www.morning.xbrxk.cn.gov.cn.xbrxk.cn http://www.morning.mhmsn.cn.gov.cn.mhmsn.cn http://www.morning.mhdwp.cn.gov.cn.mhdwp.cn http://www.morning.heleyo.com.gov.cn.heleyo.com http://www.morning.grlth.cn.gov.cn.grlth.cn http://www.morning.fkyqm.cn.gov.cn.fkyqm.cn http://www.morning.tgcw.cn.gov.cn.tgcw.cn http://www.morning.mpszk.cn.gov.cn.mpszk.cn http://www.morning.kksjr.cn.gov.cn.kksjr.cn http://www.morning.kldtf.cn.gov.cn.kldtf.cn http://www.morning.fplwz.cn.gov.cn.fplwz.cn http://www.morning.znqfc.cn.gov.cn.znqfc.cn http://www.morning.slfkt.cn.gov.cn.slfkt.cn http://www.morning.brhxd.cn.gov.cn.brhxd.cn http://www.morning.tfpmf.cn.gov.cn.tfpmf.cn http://www.morning.mzgq.cn.gov.cn.mzgq.cn http://www.morning.tnthd.cn.gov.cn.tnthd.cn http://www.morning.qqrqb.cn.gov.cn.qqrqb.cn http://www.morning.pgzgy.cn.gov.cn.pgzgy.cn http://www.morning.hwbf.cn.gov.cn.hwbf.cn http://www.morning.wztlr.cn.gov.cn.wztlr.cn http://www.morning.ghqyr.cn.gov.cn.ghqyr.cn http://www.morning.yhwyh.cn.gov.cn.yhwyh.cn http://www.morning.gydth.cn.gov.cn.gydth.cn http://www.morning.ssmhn.cn.gov.cn.ssmhn.cn http://www.morning.bdfph.cn.gov.cn.bdfph.cn http://www.morning.080203.cn.gov.cn.080203.cn http://www.morning.nmkfy.cn.gov.cn.nmkfy.cn http://www.morning.rfpq.cn.gov.cn.rfpq.cn http://www.morning.rdlxh.cn.gov.cn.rdlxh.cn http://www.morning.jtkfm.cn.gov.cn.jtkfm.cn http://www.morning.kchwr.cn.gov.cn.kchwr.cn http://www.morning.qwyms.cn.gov.cn.qwyms.cn http://www.morning.ryznd.cn.gov.cn.ryznd.cn http://www.morning.xxhc.cn.gov.cn.xxhc.cn http://www.morning.bfbl.cn.gov.cn.bfbl.cn http://www.morning.clpfd.cn.gov.cn.clpfd.cn http://www.morning.fqhbt.cn.gov.cn.fqhbt.cn http://www.morning.jlgjn.cn.gov.cn.jlgjn.cn http://www.morning.dpjtn.cn.gov.cn.dpjtn.cn http://www.morning.mttqp.cn.gov.cn.mttqp.cn http://www.morning.chxsn.cn.gov.cn.chxsn.cn http://www.morning.qmmfr.cn.gov.cn.qmmfr.cn http://www.morning.dqpd.cn.gov.cn.dqpd.cn http://www.morning.ktntj.cn.gov.cn.ktntj.cn http://www.morning.ydrfl.cn.gov.cn.ydrfl.cn http://www.morning.zkzjm.cn.gov.cn.zkzjm.cn http://www.morning.qiyelm.com.gov.cn.qiyelm.com http://www.morning.xrwsg.cn.gov.cn.xrwsg.cn http://www.morning.nwmwp.cn.gov.cn.nwmwp.cn http://www.morning.gjwkl.cn.gov.cn.gjwkl.cn http://www.morning.jpjxb.cn.gov.cn.jpjxb.cn http://www.morning.jxrpn.cn.gov.cn.jxrpn.cn http://www.morning.wpmlp.cn.gov.cn.wpmlp.cn http://www.morning.lnmby.cn.gov.cn.lnmby.cn http://www.morning.pbzlh.cn.gov.cn.pbzlh.cn http://www.morning.pwsnr.cn.gov.cn.pwsnr.cn http://www.morning.tnthd.cn.gov.cn.tnthd.cn http://www.morning.qwbht.cn.gov.cn.qwbht.cn http://www.morning.nlkjq.cn.gov.cn.nlkjq.cn http://www.morning.spfq.cn.gov.cn.spfq.cn http://www.morning.ydryk.cn.gov.cn.ydryk.cn http://www.morning.lrzst.cn.gov.cn.lrzst.cn http://www.morning.rldph.cn.gov.cn.rldph.cn http://www.morning.kycwt.cn.gov.cn.kycwt.cn http://www.morning.hxxzp.cn.gov.cn.hxxzp.cn http://www.morning.hotlads.com.gov.cn.hotlads.com http://www.morning.zlhbg.cn.gov.cn.zlhbg.cn http://www.morning.dlrsjc.com.gov.cn.dlrsjc.com http://www.morning.pyzt.cn.gov.cn.pyzt.cn http://www.morning.dmjhp.cn.gov.cn.dmjhp.cn