基于visual c++之windows核心编程代码分析(10)实现socket通信

来源:互联网 发布:vscode github 编辑:程序博客网 时间:2024/06/13 03:53
在多台计算机之间实现通信,最常见的方法有两种:Socket通信与UDP通信。
Socket是一种基于TCP/IP协议,建立稳定连接的点对点通信,它的特点是安全性高,数据
不会丢失,但是很占系统资源。
在JAVA中,ServerSocket类和Socket类为我们实现了Socket通信,建立通信的一般步骤是:
1。建立服务器
ServerSocket ss = new ServerSocket(端口号);
Socket socket = ss.accept();
这样,我们就已经建立了服务器,其中accept()方法会阻塞,知道有客户发送一个连接请求,我们可以通过socket.getInputStream()和socket.getOutputStream()来获得输入输出流,如调用socket.getInputStream()获得一个输入流,实际上这个流就是连接对方的一个输出流,流的操作与文件流操作相同,我们可以用操作文件的方法来操作它们。
2。建立客户端
Socket socket = new Socket(主机名,端口号)
客户端只需这一句代码就可以与服务器取得连接,这里的主机名应为服务器的IP地址,端口号是服务器用来监听该程序的端口,同样可以通过socket.getInputStream()和socket.getOutputStream()来获得输入输出流。在以上程序中,已经实现了一个最简单的客户端和服务器的通信。但是,还有一些问题。
首先,这个通信只执行一次,程序就将结束。因为我们只读了一次输入流,如果想要建立客户与服务器之间的稳定的会话,就要用到多线程:
Thread thread = new Thread(new Sender());
thread.start();

InputStream input = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(input));
while(true){
 br.readLine();
}
其中,Sender是一个实现了Runnable接口的类,用它来专门负责发送数据,主线程只需要不听地接受数据就行。Sender类中的run()方法应该具有以下代码:
PrintWriter pw = new PrintWriter(socket.getOutputStream());
while(true){
 pw.println(数据);
}
即使按上面的方式做了,程序还是有问题,因为它只能在一个时间内为一个客户服务,不能同时为多个客户服务,如多要想同时为多个客户服务,服务器应具有类似以下的代码:
ServerSocker ss = new ServerSocker(端口号);
socket = null;
while(true){
 socket = ss.accept();
 Thread thread1 = new Thread(new Sender());
 thread1.start();
 Thread thread2 = new Thread(new Receiver());
 thread2.start();
}
在这里,新开启了2个线程分别负责接收和发送。Receiver是一个与Sender非常相似的类,它主要用来接收数据。在客户端,我们同样应开启2个线程:
Socket socket = new Socket(服务器IP,端口号);
Sender sender = new Sender(socket);
Thread thread1 = new Thread(sender);
thread1.start();

Receiver receiver = new Receiver(socket);
Thread thread2 = new Thread(receiver);
thread2.start();

我们来亲自动手实现案例

实现客户端

[cpp] view plain copy
  1. /* 头文件 */  
  2. #include <stdio.h>  
  3. #include "winsock2.h"  
  4. /* 常量 */  
  5. #define RECV_BUFFER_SIZE 8192  
  6.   
  7. /************************************* 
  8. * main 
  9. * 功能 socket通信客户端 
  10. **************************************/  
  11. void main(int argc, char* argv[])  
  12. {  
  13.     // 变量定义  
  14.     SOCKADDR_IN clientService;// 地址  
  15.     SOCKET ConnectSocket;// socket  
  16.     WSADATA wsaData;// 库  
  17.     LPVOID recvbuf;// 接收缓存  
  18.     int bytesSent;  
  19.     int bytesRecv = 0;  
  20.     char sendbuf[32] = "get information";// 默认发送的数据  
  21.   
  22.     // 初始化socket库,  保存ws2_32.dll已经加载  
  23.     int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);  
  24.     if (iResult != NO_ERROR)  
  25.         printf("Error at WSAStartup()\n");  
  26.   
  27.     // 创建socket  
  28.     ConnectSocket = socket(AF_INET, // IPv4  
  29.         SOCK_STREAM, // 顺序的、可靠的、基于连接的、双向的数据流通信  
  30.         IPPROTO_TCP// 使用TCP协议  
  31.         );  
  32.     if (ConnectSocket == INVALID_SOCKET)  
  33.     {  
  34.         printf("Error at socket(): %ld\n", WSAGetLastError());  
  35.         WSACleanup();  
  36.         return;  
  37.     }  
  38.   
  39.     // 设置服务端的通信协议、IP地址、端口  
  40.     clientService.sin_family = AF_INET;  
  41.     clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );  
  42.     clientService.sin_port = htons( 10000 );  
  43.   
  44.     // 连接到服务端  
  45.     if ( connect(  
  46.         ConnectSocket, // socket  
  47.         (SOCKADDR*) &clientService, // 地址  
  48.         sizeof(clientService) // 地址的大小  
  49.         ) == SOCKET_ERROR)  
  50.     {  
  51.         printf( "Failed to connect(%d)\n",WSAGetLastError() );  
  52.         WSACleanup();  
  53.         return;  
  54.     }  
  55.     // 准备发送数据  
  56.     // 如果输入参数是-d,那么发送的数据是“download file”否则是"get information"  
  57.     if(argc ==2 && (!lstrcmp(argv[1], "-d")))  
  58.     {  
  59.         lstrcpyn(sendbuf, "download file", 32);  
  60.     }  
  61.     // 向服务端发送数据  
  62.     bytesSent = send( ConnectSocket, // socket  
  63.         sendbuf,// 发送的数据   
  64.         lstrlen(sendbuf)+1,// 数据长度  
  65.         0 );// 无标志  
  66.   
  67.     if(bytesSent == SOCKET_ERROR)  
  68.     {  
  69.         printf( "send error (%d)\n", WSAGetLastError());  
  70.         closesocket(ConnectSocket);  
  71.         return;  
  72.     }  
  73.     printf( "Bytes Sent: %ld\n", bytesSent );  
  74.   
  75.     // 准备接收数据  
  76.     recvbuf = HeapAlloc(GetProcessHeap(), 0, RECV_BUFFER_SIZE);  
  77.     // 循环接收  
  78.     while( bytesRecv != SOCKET_ERROR )  
  79.     {  
  80.         //Sleep(50);  
  81.         bytesRecv = recv( ConnectSocket, // socket  
  82.             recvbuf, // 接收数据缓存  
  83.             RECV_BUFFER_SIZE,// 缓存大小  
  84.             0 );// 无标志  
  85.         if ( bytesRecv == 0 )  
  86.         {  
  87.             printf( "Connection Closed.\n");  
  88.             break;  
  89.         }  
  90.         // TODO,处理接收的数据,这里只简单的将收到的数据大小显示  
  91.         printf( "Bytes Recv: %ld\n", bytesRecv );  
  92.     }  
  93.     HeapFree(GetProcessHeap(), 0, recvbuf);  
  94.     WSACleanup();  
  95.     return;  
  96. }  

实现服务端

[cpp] view plain copy
  1. /* 头文件 */  
  2. #include <winsock2.h>  
  3. #include <ws2tcpip.h>  
  4. #include <stdio.h>  
  5. /* 常量 */  
  6. #define DEFAULT_PORT "10000" // 端口  
  7. #define MAX_REQUEST 1024 // 接收数据的缓存大小  
  8. #define BUF_SIZE 4096 // 发送数据的缓存大小  
  9.   
  10. /************************************* 
  11. * CommunicationThread 
  12. * 功能    用于接收和发送数据的线程 
  13. *           为每一个连接的客户端创建一个接收发送数据的线程, 
  14. *           可以使用多个客户端同时连接到服务端 
  15. * 参数    lpParameter,SOKCET 
  16. **************************************/  
  17. DWORD WINAPI CommunicationThread(  
  18.                                  LPVOID lpParameter  
  19.                                  )  
  20. {  
  21.     DWORD dwTid = GetCurrentThreadId();  
  22.     // 获得参数sokcet  
  23.     SOCKET socket = (SOCKET)lpParameter;  
  24.     // 为接收数据分配空间  
  25.     LPSTR szRequest = HeapAlloc(GetProcessHeap(),0, MAX_REQUEST);  
  26.     int iResult;  
  27.     int bytesSent;// 用于保存send的返回值,实际发送的数据的大小  
  28.   
  29.     // 接收数据  
  30.     iResult = recv(socket, // socket  
  31.         szRequest, // 接收缓存  
  32.         MAX_REQUEST, // 缓存大小  
  33.         0);// 标志  
  34.     if (iResult == 0)// 接收数据失败,连接已经关闭  
  35.     {  
  36.         printf("Connection closing...\n");  
  37.         HeapFree(GetProcessHeap(), 0 ,szRequest);  
  38.         closesocket(socket);  
  39.         return 1;  
  40.     }  
  41.     else if (iResult == SOCKET_ERROR)// 接收数据失败,socket错误  
  42.     {  
  43.         printf("recv failed: %d\n", WSAGetLastError());  
  44.         HeapFree(GetProcessHeap(), 0 ,szRequest);  
  45.         closesocket(socket);  
  46.         return 1;  
  47.     }  
  48.     else if (iResult > 0) // 接收数据成功  
  49.     {  
  50.         // 显示接收到的数据  
  51.         printf("\tCommunicationThread(%d)\tBytes received: %d\n", dwTid, iResult);  
  52.         printf("\tCommunicationThread(%d)\trequest string is (%s)\n",dwTid, szRequest);  
  53.   
  54.         // 如果接收到的数据是"download file"  
  55.         if (lstrcmpi(szRequest, "download file") == 0)  
  56.         {  
  57.             // 读取文件download.txt将发送  
  58.             HANDLE hFile;  
  59.             LPVOID lpReadBuf; // 发送缓存  
  60.             DWORD dwBytesRead;  
  61.             DWORD dwFileSize;  
  62.             DWORD dwSendFile = 0;  
  63.             hFile = CreateFile("download.txt",  
  64.                 GENERIC_READ,  
  65.                 FILE_SHARE_READ,  
  66.                 NULL,  
  67.                 OPEN_EXISTING,  
  68.                 FILE_ATTRIBUTE_NORMAL,  
  69.                 NULL);  
  70.   
  71.             if (hFile == INVALID_HANDLE_VALUE)  
  72.             {  
  73.                 printf("\tCommunicationThread\tCould not open file (error %d)\n",   
  74.                     GetLastError());  
  75.                 send(socket, "error", 6, 0);  
  76.                 closesocket(socket);  
  77.                 return 1;  
  78.             }  
  79.             // 分配发送数据缓存  
  80.             lpReadBuf = HeapAlloc(GetProcessHeap(), 0 , BUF_SIZE);  
  81.             // 获取文件大小  
  82.             dwFileSize = GetFileSize(hFile, NULL);  
  83.             // 循环发送  
  84.             while(1)  
  85.             {  
  86.                 // 读文件到缓存  
  87.                 if(!ReadFile(hFile, lpReadBuf, BUF_SIZE, &dwBytesRead, NULL))  
  88.                 {  
  89.                     printf("\tCommunicationThread\tCould not read from file (error %d)\n",   
  90.                         GetLastError());  
  91.                     closesocket(socket);  
  92.                     CloseHandle(hFile);  
  93.                     return 1;  
  94.                 }  
  95.                 // 发送读取的文件数据  
  96.                 bytesSent = send(socket, lpReadBuf, dwBytesRead, 0);  
  97.                 if( bytesSent == SOCKET_ERROR)  
  98.                 {  
  99.                     printf("\tCommunicationThread\tsend error %d\n",   
  100.                         WSAGetLastError());  
  101.                     closesocket(socket);  
  102.                     CloseHandle(hFile);  
  103.                     return 1;  
  104.                 }  
  105.                 // 显示发送数据的大小  
  106.                 printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid,  bytesSent);  
  107.                 // 累加,已经发送的大小  
  108.                 dwSendFile += dwBytesRead;  
  109.                 // 如果所有文件数据都已经发送  
  110.                 if(dwSendFile == dwFileSize)  
  111.                 {  
  112.                     printf("\tCommunicationThread\tFile download ok\n");  
  113.                     break;// 退出循环  
  114.                 }  
  115.             }  
  116.             // 释放内存、关闭连接,关闭文件  
  117.             HeapFree(GetProcessHeap(), 0 , lpReadBuf);  
  118.             CloseHandle(hFile);  
  119.             closesocket(socket);  
  120.         }  
  121.         // 如果接收到的数据是"get information"  
  122.         else if (lstrcmpi(szRequest, "get information") == 0)  
  123.         {  
  124.             // 发送数据  
  125.             bytesSent = send(socket, // socket  
  126.                 "this is information"// 数据  
  127.                 lstrlen("this is information")+1, // 数据长度  
  128.                 0);// 标志  
  129.             // 判断是否成功  
  130.             if( bytesSent == SOCKET_ERROR)  
  131.             {  
  132.                 printf("\tCommunicationThread\tsend error %d\n",   
  133.                     WSAGetLastError());  
  134.                 closesocket(socket);  
  135.                 return 1;  
  136.             }  
  137.             printf("\tCommunicationThread(%d)\tsend %d bytes\n",dwTid, bytesSent);  
  138.         }  
  139.         else// 收到未知数据  
  140.         {  
  141.             printf ("unreferenced request\n");  
  142.         }  
  143.     }  
  144.     // 释放接收数据缓存,关闭socket  
  145.     HeapFree(GetProcessHeap(), 0 ,szRequest);  
  146.     closesocket(socket);  
  147.     return 0;  
  148. }  
  149.   
  150. /************************************* 
  151. * int __cdecl main(void) 
  152. * 功能    socket服务端 
  153. **************************************/  
  154. int __cdecl main(void)  
  155. {  
  156.     WSADATA wsaData;  
  157.     SOCKET ListenSocket = INVALID_SOCKET;// 监听socket  
  158.     SOCKET ClientSocket = INVALID_SOCKET;// 连接socket  
  159.     struct addrinfo *result = NULL,  
  160.         hints;  
  161.     int iResult;// 保存返回结果  
  162.   
  163.     // 初始化Winsock,保证Ws2_32.dll已经加载  
  164.     iResult = WSAStartup(MAKEWORD(2,2), &wsaData);  
  165.     if (iResult != 0)  
  166.     {  
  167.         printf("WSAStartup failed: %d\n", iResult);  
  168.         return 1;  
  169.     }  
  170.     // 地址  
  171.     ZeroMemory(&hints, sizeof(hints));  
  172.     hints.ai_family = AF_INET;  
  173.     hints.ai_socktype = SOCK_STREAM;  
  174.     hints.ai_protocol = IPPROTO_TCP;  
  175.     hints.ai_flags = AI_PASSIVE;  
  176.   
  177.     // 获取主机地址,保证网络协议可用等  
  178.     iResult = getaddrinfo(NULL, // 本机  
  179.         DEFAULT_PORT, // 端口  
  180.         &hints, // 使用的网络协议,连接类型等  
  181.         &result);// 结果  
  182.     if ( iResult != 0 )  
  183.     {  
  184.         printf("getaddrinfo failed: %d\n", iResult);  
  185.         WSACleanup();  
  186.         return 1;  
  187.     }  
  188.   
  189.     // 创建socket,用于监听  
  190.     ListenSocket = socket(  
  191.         result->ai_family, // 网络协议,AF_INET,IPv4  
  192.         result->ai_socktype, // 类型,SOCK_STREAM  
  193.         result->ai_protocol);// 通信协议,TCP  
  194.     if (ListenSocket == INVALID_SOCKET)  
  195.     {  
  196.         printf("socket failed: %ld\n", WSAGetLastError());  
  197.         freeaddrinfo(result);  
  198.         WSACleanup();  
  199.         return 1;  
  200.     }  
  201.     // 绑定到端口  
  202.     iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);  
  203.     if (iResult == SOCKET_ERROR)  
  204.     {  
  205.         printf("bind failed: %d\n", WSAGetLastError());  
  206.         freeaddrinfo(result);  
  207.         closesocket(ListenSocket);  
  208.         WSACleanup();  
  209.         return 1;  
  210.     }  
  211.     printf("bind\n");  
  212.   
  213.     freeaddrinfo(result);// reuslt不再使用  
  214.   
  215.     // 开始监听  
  216.     iResult = listen(ListenSocket, SOMAXCONN);  
  217.     printf("start listen......\n");  
  218.     if (iResult == SOCKET_ERROR)  
  219.     {  
  220.         printf("listen failed: %d\n", WSAGetLastError());  
  221.         closesocket(ListenSocket);  
  222.         WSACleanup();  
  223.         return 1;  
  224.     }  
  225.     while (1)  
  226.     {  
  227.         // 接收客户端的连接,accept函数会等待,直到连接建立  
  228.         printf("ready to accept\n");  
  229.         ClientSocket = accept(ListenSocket, NULL, NULL);  
  230.         // accept函数返回,说明已经有客户端连接  
  231.         // 返回连接socket  
  232.         printf("accept a connetion\n");  
  233.         if (ClientSocket == INVALID_SOCKET)  
  234.         {  
  235.             printf("accept failed: %d\n", WSAGetLastError());  
  236.             closesocket(ListenSocket);  
  237.             break;// 等待连接错误,退出循环  
  238.         }  
  239.         // 为每一个连接创建一个数据发送的接收线程,  
  240.         // 使服务端又可以立即接收其他客户端的连接  
  241.         if(!CreateThread(  
  242.             NULL,  
  243.             0,  
  244.             CommunicationThread, // 线程函数  
  245.             (LPVOID)ClientSocket, // 将socket作为参数  
  246.             0,  
  247.             NULL))  
  248.         {  
  249.             printf("Create Thread error (%d)", GetLastError());  
  250.             break;  
  251.         }  
  252.     }  
  253.     // 循环退出,释放DLL。  
  254.     WSACleanup();  
  255.     return 0;  
  256. }  


 


[cpp] view plain copy
  1. /* 头文件 */  
  2. #include <winsock2.h>  
  3. #include <ws2tcpip.h>  
  4. #include <stdio.h>  
  5. /* 常量 */  
  6. #define DEFAULT_PORT "10000" // 端口  
  7. #define MAX_REQUEST 1024 // 接收数据的缓存大小  
  8. #define BUF_SIZE 4096 // 发送数据的缓存大小  
  9.   
  10. /************************************* 
  11. * CommunicationThread 
  12. * 功能    用于接收和发送数据的线程 
  13. *           为每一个连接的客户端创建一个接收发送数据的线程, 
  14. *           可以使用多个客户端同时连接到服务端 
  15. * 参数    lpParameter,SOKCET 
  16. **************************************/  
  17. DWORD WINAPI CommunicationThread(  
  18.                                  LPVOID lpParameter  
  19.                                  )  
  20. {  
  21.     DWORD dwTid = GetCurrentThreadId();  
  22.     // 获得参数sokcet  
  23.     SOCKET socket = (SOCKET)lpParameter;  
  24.     // 为接收数据分配空间  
  25.     LPSTR szRequest = HeapAlloc(GetProcessHeap(),0, MAX_REQUEST);  
  26.     int iResult;  
  27.     int bytesSent;// 用于保存send的返回值,实际发送的数据的大小  
  28.   
  29.     // 接收数据  
  30.     iResult = recv(socket, // socket  
  31.         szRequest, // 接收缓存  
  32.         MAX_REQUEST, // 缓存大小  
  33.         0);// 标志  
  34.     if (iResult == 0)// 接收数据失败,连接已经关闭  
  35.     {  
  36.         printf("Connection closing...\n");  
  37.         HeapFree(GetProcessHeap(), 0 ,szRequest);  
  38.         closesocket(socket);  
  39.         return 1;  
  40.     }  
  41.     else if (iResult == SOCKET_ERROR)// 接收数据失败,socket错误  
  42.     {  
  43.         printf("recv failed: %d\n", WSAGetLastError());  
  44.         HeapFree(GetProcessHeap(), 0 ,szRequest);  
  45.         closesocket(socket);  
  46.         return 1;  
  47.     }  
  48.     else if (iResult > 0) // 接收数据成功  
  49.     {  
  50.         // 显示接收到的数据  
  51.         printf("\tCommunicationThread(%d)\tBytes received: %d\n", dwTid, iResult);  
  52.         printf("\tCommunicationThread(%d)\trequest string is (%s)\n",dwTid, szRequest);  
  53.   
  54.         // 如果接收到的数据是"download file"  
  55.         if (lstrcmpi(szRequest, "download file") == 0)  
  56.         {  
  57.             // 读取文件download.txt将发送  
  58.             HANDLE hFile;  
  59.             LPVOID lpReadBuf; // 发送缓存  
  60.             DWORD dwBytesRead;  
  61.             DWORD dwFileSize;  
  62.             DWORD dwSendFile = 0;  
  63.             hFile = CreateFile("download.txt",  
  64.                 GENERIC_READ,  
  65.                 FILE_SHARE_READ,  
  66.                 NULL,  
  67.                 OPEN_EXISTING,  
  68.                 FILE_ATTRIBUTE_NORMAL,  
  69.                 NULL);  
  70.   
  71.             if (hFile == INVALID_HANDLE_VALUE)  
  72.             {  
  73.                 printf("\tCommunicationThread\tCould not open file (error %d)\n",   
  74.                     GetLastError());  
  75.                 send(socket, "error", 6, 0);  
  76.                 closesocket(socket);  
  77.                 return 1;  
  78.             }  
  79.             // 分配发送数据缓存  
  80.             lpReadBuf = HeapAlloc(GetProcessHeap(), 0 , BUF_SIZE);  
  81.             // 获取文件大小  
  82.             dwFileSize = GetFileSize(hFile, NULL);  
  83.             // 循环发送  
  84.             while(1)  
  85.             {  
  86.                 // 读文件到缓存  
  87.                 if(!ReadFile(hFile, lpReadBuf, BUF_SIZE, &dwBytesRead, NULL))  
  88.                 {  
  89.                     printf("\tCommunicationThread\tCould not read from file (error %d)\n",   
  90.                         GetLastError());  
  91.                     closesocket(socket);  
  92.                     CloseHandle(hFile);  
  93.                     return 1;  
  94.                 }  
  95.                 // 发送读取的文件数据  
  96.                 bytesSent = send(socket, lpReadBuf, dwBytesRead, 0);  
  97.                 if( bytesSent == SOCKET_ERROR)  
  98.                 {  
  99.                     printf("\tCommunicationThread\tsend error %d\n",   
  100.                         WSAGetLastError());  
  101.                     closesocket(socket);  
  102.                     CloseHandle(hFile);  
  103.                     return 1;  
  104.                 }  
  105.                 // 显示发送数据的大小  
  106.                 printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid,  bytesSent);  
  107.                 // 累加,已经发送的大小  
  108.                 dwSendFile += dwBytesRead;  
  109.                 // 如果所有文件数据都已经发送  
  110.                 if(dwSendFile == dwFileSize)  
  111.                 {  
  112.                     printf("\tCommunicationThread\tFile download ok\n");  
  113.                     break;// 退出循环  
  114.                 }  
  115.             }  
  116.             // 释放内存、关闭连接,关闭文件  
  117.             HeapFree(GetProcessHeap(), 0 , lpReadBuf);  
  118.             CloseHandle(hFile);  
  119.             closesocket(socket);  
  120.         }  
  121.         // 如果接收到的数据是"get information"  
  122.         else if (lstrcmpi(szRequest, "get information") == 0)  
  123.         {  
  124.             // 发送数据  
  125.             bytesSent = send(socket, // socket  
  126.                 "this is information"// 数据  
  127.                 lstrlen("this is information")+1, // 数据长度  
  128.                 0);// 标志  
  129.             // 判断是否成功  
  130.             if( bytesSent == SOCKET_ERROR)  
  131.             {  
  132.                 printf("\tCommunicationThread\tsend error %d\n",   
  133.                     WSAGetLastError());  
  134.                 closesocket(socket);  
  135.                 return 1;  
  136.             }  
  137.             printf("\tCommunicationThread(%d)\tsend %d bytes\n",dwTid, bytesSent);  
  138.         }  
  139.         else// 收到未知数据  
  140.         {  
  141.             printf ("unreferenced request\n");  
  142.         }  
  143.     }  
  144.     // 释放接收数据缓存,关闭socket  
  145.     HeapFree(GetProcessHeap(), 0 ,szRequest);  
  146.     closesocket(socket);  
  147.     return 0;  
  148. }  
  149.   
  150. /************************************* 
  151. * int __cdecl main(void) 
  152. * 功能    socket服务端 
  153. **************************************/  
  154. int __cdecl main(void)  
  155. {  
  156.     WSADATA wsaData;  
  157.     SOCKET ListenSocket = INVALID_SOCKET;// 监听socket  
  158.     SOCKET ClientSocket = INVALID_SOCKET;// 连接socket  
  159.     struct addrinfo *result = NULL,  
  160.         hints;  
  161.     int iResult;// 保存返回结果  
  162.   
  163.     // 初始化Winsock,保证Ws2_32.dll已经加载  
  164.     iResult = WSAStartup(MAKEWORD(2,2), &wsaData);  
  165.     if (iResult != 0)  
  166.     {  
  167.         printf("WSAStartup failed: %d\n", iResult);  
  168.         return 1;  
  169.     }  
  170.     // 地址  
  171.     ZeroMemory(&hints, sizeof(hints));  
  172.     hints.ai_family = AF_INET;  
  173.     hints.ai_socktype = SOCK_STREAM;  
  174.     hints.ai_protocol = IPPROTO_TCP;  
  175.     hints.ai_flags = AI_PASSIVE;  
  176.   
  177.     // 获取主机地址,保证网络协议可用等  
  178.     iResult = getaddrinfo(NULL, // 本机  
  179.         DEFAULT_PORT, // 端口  
  180.         &hints, // 使用的网络协议,连接类型等  
  181.         &result);// 结果  
  182.     if ( iResult != 0 )  
  183.     {  
  184.         printf("getaddrinfo failed: %d\n", iResult);  
  185.         WSACleanup();  
  186.         return 1;  
  187.     }  
  188.   
  189.     // 创建socket,用于监听  
  190.     ListenSocket = socket(  
  191.         result->ai_family, // 网络协议,AF_INET,IPv4  
  192.         result->ai_socktype, // 类型,SOCK_STREAM  
  193.         result->ai_protocol);// 通信协议,TCP  
  194.     if (ListenSocket == INVALID_SOCKET)  
  195.     {  
  196.         printf("socket failed: %ld\n", WSAGetLastError());  
  197.         freeaddrinfo(result);  
  198.         WSACleanup();  
  199.         return 1;  
  200.     }  
  201.     // 绑定到端口  
  202.     iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);  
  203.     if (iResult == SOCKET_ERROR)  
  204.     {  
  205.         printf("bind failed: %d\n", WSAGetLastError());  
  206.         freeaddrinfo(result);  
  207.         closesocket(ListenSocket);  
  208.         WSACleanup();  
  209.         return 1;  
  210.     }  
  211.     printf("bind\n");  
  212.   
  213.     freeaddrinfo(result);// reuslt不再使用  
  214.   
  215.     // 开始监听  
  216.     iResult = listen(ListenSocket, SOMAXCONN);  
  217.     printf("start listen......\n");  
  218.     if (iResult == SOCKET_ERROR)  
  219.     {  
  220.         printf("listen failed: %d\n", WSAGetLastError());  
  221.         closesocket(ListenSocket);  
  222.         WSACleanup();  
  223.         return 1;  
  224.     }  
  225.     while (1)  
  226.     {  
  227.         // 接收客户端的连接,accept函数会等待,直到连接建立  
  228.         printf("ready to accept\n");  
  229.         ClientSocket = accept(ListenSocket, NULL, NULL);  
  230.         // accept函数返回,说明已经有客户端连接  
  231.         // 返回连接socket  
  232.         printf("accept a connetion\n");  
  233.         if (ClientSocket == INVALID_SOCKET)  
  234.         {  
  235.             printf("accept failed: %d\n", WSAGetLastError());  
  236.             closesocket(ListenSocket);  
  237.             break;// 等待连接错误,退出循环  
  238.         }  
  239.         // 为每一个连接创建一个数据发送的接收线程,  
  240.         // 使服务端又可以立即接收其他客户端的连接  
  241.         if(!CreateThread(  
  242.             NULL,  
  243.             0,  
  244.             CommunicationThread, // 线程函数  
  245.             (LPVOID)ClientSocket, // 将socket作为参数  
  246.             0,  
  247.             NULL))  
  248.         {  
  249.             printf("Create Thread error (%d)", GetLastError());  
  250.             break;  
  251.         }  
  252.     }  
  253.     // 循环退出,释放DLL。  
  254.     WSACleanup();  
  255.     return 0;  
  256. }  
0 0