windows socket编程入门示例3

来源:互联网 发布:手机怎样制作软件 编辑:程序博客网 时间:2024/06/05 18:18
// Lock.h#ifndef _Lock_H#define _Lock_H#include <windows.h>class CriticalSection{private:CRITICAL_SECTION g_cs;     //临界区  public:CriticalSection();~CriticalSection();void Lock();void UnLock();};#endif// Lock.cpp#include "Lock.h"CriticalSection::CriticalSection(){InitializeCriticalSection(&g_cs);    //必须先初始化临界区  }CriticalSection::~CriticalSection(){DeleteCriticalSection(&g_cs);//删除临界区  }void CriticalSection::Lock(){EnterCriticalSection(&g_cs);//进入临界区(申请钥匙,得到钥匙)  }void CriticalSection::UnLock(){LeaveCriticalSection(&g_cs);//离开(放弃钥匙,不再拥有)  }// tcpSocketSelect.cpp#include <stdio.h>#include <winsock2.h>#include "Lock.h"#pragma comment(lib,"ws2_32.lib")#define IP_ADDRESS "127.0.0.1"#define PORT5678#define MSGSIZE     8192// window操作系统默认socket收发缓存大小是8Kstatic volatile bool isRunning;static int volatile g_iTotalConn = 0;static SOCKET g_CliSocketArr[FD_SETSIZE];// FD是File Describle文件描述符,也就是socket文件描述符(句柄)CriticalSection criticalSectionLock;class SelectModel{public:static DWORD WINAPI  WorkerThread(LPVOID lpParameter); // 服务器端工作线程int Process();};int SelectModel::Process(){int retCode;WORD wVersionRequested;WSADATA wsaData;SOCKET      sListen, sClient;SOCKADDR_IN local, client;int         iaddrSize = sizeof(SOCKADDR_IN);DWORD       dwThreadId;// Initialize Windows socket librarywVersionRequested = MAKEWORD(2, 2);retCode = WSAStartup(wVersionRequested, &wsaData);if (retCode != 0){fprintf(stderr, "Load WSADTATA failed!\n");return -1;}if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){fprintf(stderr, "WSADTATA version error!\n");WSACleanup();return -1;}// Create listening socketsListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sListen == INVALID_SOCKET){fprintf(stderr, "invalid socket !\n");WSACleanup();return -1;}local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);local.sin_family = AF_INET;local.sin_port = htons(PORT);int opt = 1;retCode = setsockopt(sListen, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));if (retCode < 0){printf("setsockopt Failed.\n");closesocket(sListen);WSACleanup();return -1;}retCode = bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));if (retCode == SOCKET_ERROR){printf("bind error !");closesocket(sListen);WSACleanup();return -1;}retCode = listen(sListen, 16);if (retCode == SOCKET_ERROR){printf("listen error !");closesocket(sListen);WSACleanup();return -1;}isRunning = true;// Create worker threadHANDLE serviceSubThread = CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);if (serviceSubThread == NULL){fprintf(stderr, "Create service sub thread failed!\n");goto END;}fprintf(stderr, "Server is running......\n");while (TRUE){sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);if (sClient == INVALID_SOCKET){fprintf(stderr, "Invalid socket, continue to accept new socket!\n");continue;}criticalSectionLock.Lock();if (g_iTotalConn < FD_SETSIZE){g_CliSocketArr[g_iTotalConn++] = sClient;printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));}else{closesocket(sClient);printf("refuse client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));}criticalSectionLock.UnLock();}END:closesocket(sListen);WSACleanup();return 0;}DWORD  SelectModel::WorkerThread(LPVOID lpParam){int            i = 0;fd_set         fdread;int            ret = 0;struct timeval tv = { 1, 0 };// 1是阻塞等待1秒钟返回一次,后面的0是0毫秒char           szMessage[MSGSIZE];while (isRunning){FD_ZERO(&fdread);//将fdread初始化空集int totalConn = g_iTotalConn;for (i = 0; i < totalConn; i++)// 可以在这里分段处理64个,用以支持多于64个的连接select.FD_SET(g_CliSocketArr[i], &fdread);//将要检查的套接口加入到集合中ret = select(MSGSIZE + 1, &fdread, NULL, NULL, &tv);//每隔一段时间,检查可读性的套接口,将可读的拷贝到fdread里面if (ret == 0)continue;for (i = 0; i < totalConn; i++){if (FD_ISSET(g_CliSocketArr[i], &fdread)) //如果可读{// A read event happened on g_CliSocketArrret = recv(g_CliSocketArr[i], szMessage, MSGSIZE, 0);if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)){// Client socket closedprintf("Client socket %d closed.\n", g_CliSocketArr[i]);closesocket(g_CliSocketArr[i]);criticalSectionLock.Lock();for (int j = i; j < g_iTotalConn - 1; j++)g_CliSocketArr[j] = g_CliSocketArr[j + 1];g_iTotalConn--;i--;totalConn--;criticalSectionLock.UnLock();}else{printf("ret = %d \n", ret);if (ret == MSGSIZE || ret < 0){fprintf(stderr, "an error happened.\n");closesocket(g_CliSocketArr[i]);criticalSectionLock.Lock();for (int j = i; j < g_iTotalConn - 1; j++)g_CliSocketArr[j] = g_CliSocketArr[j + 1];g_iTotalConn--;i--;totalConn--;criticalSectionLock.UnLock();}else{szMessage[ret] = '\0';// 根据需要处理接收到的消息printf("Received a message from client:%s\n", szMessage);// 根据需要是否需要发送消息send(g_CliSocketArr[i], szMessage, strlen(szMessage), 0);}}}// 可读//else if (FD_ISSET(g_CliSocketArr[i], &fdread))}// for}// whilereturn 0;}int main(){SelectModel tcpServer;tcpServer.Process();return 0;}// tcpSocketSelectClient.cpp#include <WINSOCK2.H>#include <stdio.h>#pragma  comment(lib,"ws2_32.lib")#define IP_ADDRESS "127.0.0.1"#define PORT5678#define MSGSIZE        8192 // window操作系统默认socket收发缓存大小是8KWSADATA     wsaData;SOCKET      sClient;SOCKADDR_IN server;char        szMessage[MSGSIZE];static void CheckBuffer(SOCKET &socket){//window 7,sock2,默认内核发送缓存和接收缓存都是8K.int sendbuflen = 0;int len = sizeof(sendbuflen);getsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char*)&sendbuflen, &len);printf("default,sendbuf:%d\n", sendbuflen);getsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&sendbuflen, &len);printf("default,recvbuf:%d\n", sendbuflen);/*sendbuflen = 10240;setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, len);  */}static bool LoadWSAData(WSADATA &wsaData){// Initialize Windows socket library  WORD wVersionRequested = MAKEWORD(2, 2);// MAKEWORD的作用,类似下面WORD wHigh = 2;WORD wLow = 2;WORD wAll = ((wHigh << 8) | wLow);// 初始化只需要传入版本号,和WSADATA就可以了int reqErr = ::WSAStartup(wVersionRequested, &wsaData);if (reqErr != 0){printf("加载请求指定版本的windows socket api DLL 失败");return false;}/* Confirm that the WinSock DLL supports 2.2.*//* Note that if the DLL supports versions greater    *//* than 2.2 in addition to 2.2, it will still return *//* 2.2 in wVersion since that is the version we      *//* requested.                                        */if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {/* Tell the user that we could not find a usable *//* WinSock DLL.                                  */printf("Could not find a usable version of Winsock.dll\n");::WSACleanup();return false;}else{printf("The Winsock 2.2 dll was found okay\n");return true;}}static void ReleaseWSAData(){::WSACleanup();}int main(){int nLen = sizeof(SOCKADDR_IN);if (!LoadWSAData(wsaData)){fprintf(stderr, "Load WSADTATA failed!\n");return 0;}sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 协议族,socket类型,具体协议if (INVALID_SOCKET == sClient){ReleaseWSAData();printf("Get Socket Error: INVALID_SOCKET.\n");return 0;}CheckBuffer(sClient);memset(&server, 0, sizeof(SOCKADDR_IN));server.sin_family = AF_INET;server.sin_addr.S_un.S_addr = inet_addr(IP_ADDRESS);server.sin_port = htons(PORT);int nConnect = connect(sClient, (struct sockaddr *)&server, sizeof(SOCKADDR_IN));if (SOCKET_ERROR == nConnect){printf("Socket connnect Error:%d\n", WSAGetLastError());closesocket(sClient);ReleaseWSAData();return 0;}int messageLength = 0;while (TRUE){memset(szMessage, 0, sizeof(szMessage));printf("请输入发送到服务器的消息:");fgets(szMessage, sizeof(szMessage), stdin);messageLength = strlen(szMessage);if (messageLength < 2){fprintf(stderr, "你没有输入消息!\n");continue;}int retCode = send(sClient, szMessage, strlen(szMessage), 0);// strlen求得的字符串长度不包含'\0'if (SOCKET_ERROR == retCode)printf("Send Copy data kernel buffer is too small or network shutdown!\n");if (retCode == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET){fprintf(stderr, "Server has disconneted, send data to server failed!\n");break;}else if (retCode == SOCKET_ERROR){printf("Send data to Server failed!\n");break;}if (retCode != SOCKET_ERROR)printf("Send data to Server finished.\n");int nRecvRes = recv(sClient, szMessage, MSGSIZE, 0);if (nRecvRes > 0){szMessage[nRecvRes] = '\0';printf("接收到服务器发来的消息 : %s\n", szMessage);}else if (nRecvRes == 0 || (nRecvRes == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)){printf("Server Connection Close.\n");break;}else if (nRecvRes == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK){fprintf(stdout, "非阻塞类型返回\n");continue;}else{printf("Unknow recv error code: %d\n", WSAGetLastError());break;}}closesocket(sClient);ReleaseWSAData();return 0;}

原创粉丝点击