服务端程序:
[cpp] view plaincopyprint?
1. #include <stdio.h>
2. #include <winsock2.h>
3. #pragma comment(lib, "ws2_32.lib")
4.
5. int totalSockets = 0; // socket的总数
6. SOCKET socketArray[100]; // socket组成的数组, 假设最多有100个socket吧
7.
8. // 日志打印
9. void log(const char *pStr)
10.{
11. FILE *fp = fopen("log.txt", "a");
12. fprintf(fp, "log:%s\n", pStr);
13. fclose(fp);
14.}
15.
16.// 创建socket
17.void addToSocketArr(SOCKET s)
18.{
19. socketArray[totalSockets] = s;
20. totalSockets++;
21.}
22.
23.// 启动服务器
24.int main()
25.{
26. log("into main");
27.
28. // 网络初始化
29. WSADATA wsaData;
30. WSAStartup(MAKEWORD(1, 1), &wsaData);
31.
32. // 创建socket
33. SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);
34. addToSocketArr(listenSocket);
35.
36. // 服务地信息
37. SOCKADDR_IN srvAddr;
38. srvAddr.sin_family = AF_INET;
39. srvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
40. srvAddr.sin_port = htons(8888);
41.
42. // 绑定
43. bind(listenSocket, (SOCKADDR*)&srvAddr, sizeof(srvAddr));
44.
45. // 监听
46. listen(listenSocket, 5);
47.
48. // 设置socket为非阻塞模式
49. unsigned long nonBlock = 1;
50. ioctlsocket(listenSocket, FIONBIO, &nonBlock);
51.
52. while(1)
53. {
54. // 读集, 要记得清零初始化
55. FD_SET readSet;
56. FD_ZERO(&readSet);
57.
58. // 将每个socket都塞入读集, 便于让内核来监测这些socket
59. int i = 0;
60. for(i = 0; i < totalSockets; i++)
61. {
62. FD_SET(socketArray[i], &readSet);
63. }
64.
65. // 应用程序通知内核来监测读集中的socket, 最后的NULL表示超时时间无限长
66. int total = select(0, &readSet, NULL, NULL, NULL);
67.
68. // 我们不考虑select失败, 那么程序到这里, 说明读集中必有socket处于"就绪状态"
69. for(i = 0; i < totalSockets; i++)
70. {
71. char szTmp[20] = {0};
72. sprintf(szTmp, "%d", i);
73. log(szTmp);
74.
75. if(socketArray[i] == listenSocket) // 对监听的socket进行判断
76. {
77. log("socketArray[i] == listenSocket");
78.
79. if(FD_ISSET(listenSocket, &readSet)) // 如果该socket在可读集中, 则表明有客户端来连接
80. {
81.
82. log("listenSocket, socketArray[i] == listenSocket");
83.
84. // 接收来自于客户端的connect请求
85. SOCKADDR_IN addrClient;
86. int len = sizeof(SOCKADDR);
87. SOCKET acceptSocket = 0;
88. acceptSocket = accept(listenSocket,(SOCKADDR*)&addrClient, &len);
89.
90. // 设置为非阻塞模式
91. nonBlock = 1;
92. ioctlsocket(acceptSocket, FIONBIO, &nonBlock);
93.
94. // 添加到socket数组中
95. addToSocketArr(acceptSocket);
96. }
97.
98. continue;
99. }
100.
101.
102. // 注意:上面的listenSocket是不负责通信的, 下面的一些socket都是负责通信的socket
103.
104.
105. // 如果通信socket处于读就绪状态
106. if (FD_ISSET(socketArray[i], &readSet))
107. {
108. log("to receive");
109.
110. char szRecvBuf[1024] = {0};
111. recv(socketArray[i], szRecvBuf, sizeof(szRecvBuf) - 1, 0);
112. printf("socketArray[i] is %d, %s\n", socketArray[i], szRecvBuf);
113. }
114. }
115. }
116.
117. // 省略了关闭socket等后续操作
118.
119. return 0;
120. }
#include<stdio.h>
#include<winsock2.h>
#pragmacomment(lib, "ws2_32.lib")
inttotalSockets = 0; // socket的总数
SOCKETsocketArray[100]; // socket组成的数组,假设最多有100个socket吧
// 日志打印
voidlog(const char *pStr)
{
FILE *fp = fopen("log.txt","a");
fprintf(fp, "log:%s\n", pStr);
fclose(fp);
}
// 创建socket
voidaddToSocketArr(SOCKET s)
{
socketArray[totalSockets] = s;
totalSockets++;
}
// 启动服务器
intmain()
{
log("into main");
// 网络初始化
WSADATA wsaData;
WSAStartup(MAKEWORD(1, 1), &wsaData);
// 创建socket
SOCKET listenSocket = socket(AF_INET,SOCK_STREAM, 0);
addToSocketArr(listenSocket);
// 服务地信息
SOCKADDR_IN srvAddr;
srvAddr.sin_family = AF_INET;
srvAddr.sin_addr.s_addr =htonl(INADDR_ANY);
srvAddr.sin_port = htons(8888);
// 绑定
bind(listenSocket, (SOCKADDR*)&srvAddr,sizeof(srvAddr));
// 监听
listen(listenSocket, 5);
// 设置socket为非阻塞模式
unsigned long nonBlock = 1;
ioctlsocket(listenSocket, FIONBIO,&nonBlock);
while(1)
{
// 读集, 要记得清零初始化
FD_SET readSet;
FD_ZERO(&readSet);
// 将每个socket都塞入读集, 便于让内核来监测这些socket
int i = 0;
for(i = 0; i < totalSockets;i++)
{
FD_SET(socketArray[i], &readSet);
}
// 应用程序通知内核来监测读集中的socket, 最后的NULL表示超时时间无限长
int total = select(0, &readSet, NULL, NULL,NULL);
// 我们不考虑select失败, 那么程序到这里, 说明读集中必有socket处于"就绪状态"
for(i = 0; i < totalSockets;i++)
{
char szTmp[20] = {0};
sprintf(szTmp, "%d", i);
log(szTmp);
if(socketArray[i] == listenSocket) // 对监听的socket进行判断
{
log("socketArray[i] ==listenSocket");
if(FD_ISSET(listenSocket, &readSet)) // 如果该socket在可读集中, 则表明有客户端来连接
{
log("listenSocket, socketArray[i] ==listenSocket");
// 接收来自于客户端的connect请求
SOCKADDR_IN addrClient;
int len = sizeof(SOCKADDR);
SOCKET acceptSocket = 0;
acceptSocket =accept(listenSocket,(SOCKADDR*)&addrClient, &len);
// 设置为非阻塞模式
nonBlock = 1;
ioctlsocket(acceptSocket, FIONBIO,&nonBlock);
// 添加到socket数组中
addToSocketArr(acceptSocket);
}
continue;
}
// 注意:上面的listenSocket是不负责通信的, 下面的一些socket都是负责通信的socket
// 如果通信socket处于读就绪状态
if (FD_ISSET(socketArray[i],&readSet))
{
log("to receive");
char szRecvBuf[1024] = {0};
recv(socketArray[i], szRecvBuf,sizeof(szRecvBuf) - 1, 0);
printf("socketArray[i] is %d, %s\n",socketArray[i], szRecvBuf);
}
}
}
// 省略了关闭socket等后续操作
return 0;
}
启动服务端。
再看客户端程序:
[cpp] view plaincopyprint?
1. #include <winsock2.h>
2. #include <stdio.h>
3. #pragma comment(lib, "ws2_32.lib")
4.
5. int main()
6. {
7. WORD wVersionRequested;
8. WSADATA wsaData;
9. wVersionRequested = MAKEWORD(1, 1);
10.
11. WSAStartup( wVersionRequested, &wsaData );
12.
13. SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
14.
15. SOCKADDR_IN addrSrv;
16. addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
17. addrSrv.sin_family = AF_INET;
18. addrSrv.sin_port = htons(8888);
19.
20. connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
21.
22.
23. while(1)
24. {
25. char szSendBuf[100] = {0};
26. scanf("%s", szSendBuf);
27. send(sockClient, szSendBuf, strlen(szSendBuf) + 1, 0);
28. }
29.
30. closesocket(sockClient);
31. WSACleanup();
32.
33. return 0;
34.}