1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#include <stdio.h>
#include<WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib") //加载ws2_32.lib库
int main()
{
WSADATA wsadata;
WORD SockVersion = MAKEWORD(2,2);//初始化socker的版本
if (WSAStartup(SockVersion,&wsadata)!=0)//WSAStartup是绑定socket版本号,指定操作系统调用那个版本的方法
{
printf("WSAStartup fail\n");
return -1;
}
//创建scoket
SOCKET ScoketFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ScoketFd == INVALID_SOCKET)
{
printf("socket error !");
return -1;
}
//绑定IP和端口
struct sockaddr_in SockAddr;
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(1111);
SockAddr.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(ScoketFd, (SOCKADDR*)&SockAddr, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
printf("bind error !\n");
return -1;
}
//开始监听
if (listen(ScoketFd, 10) == SOCKET_ERROR)
{
printf("listen error !\n");
return -1;
}
// select模型
fd_set AllSocketSet; //创建一个文件集合
FD_ZERO(&AllSocketSet); //清空集合
FD_SET(ScoketFd,&AllSocketSet);//将ScoketFd加入sock集合
int ret = 0;
//接收数据
SOCKET ClientConFd;
struct sockaddr_in ClientAddr;
int nSize = sizeof(ClientAddr);
char RevData[1024] = { 0 };
while (1)
{
//设置监听fd可读事件
fd_set ReadFd;
fd_set WriteFd;
FD_ZERO(&ReadFd);
FD_ZERO(&WriteFd);
ReadFd = AllSocketSet;
WriteFd = AllSocketSet;
ret = select(0, &ReadFd, &WriteFd, NULL, NULL);//第一个参数nfds被忽略,是为了兼容版本
if (ret == SOCKET_ERROR)
{
printf("select error\n");
return -1;
}
if (FD_ISSET(ScoketFd, &ReadFd)) //检查ScoketFd是否在这个集合里面,
{ //select将更新这个集合,把其中不可读的套节字去掉
//只保留符合条件的套节字在这个集合里面
printf("start accept new connect\n");
ClientConFd = accept(ScoketFd, (SOCKADDR*)&ClientAddr, &nSize);//等待连接,连接后会产生一个行的fd
if (ClientConFd == INVALID_SOCKET)
{
printf("accept error !\n");
return -1;
}
else
{
FD_SET(ClientConFd, &AllSocketSet);//将新产生的fd加入到原先的集合中
}
}
for (u_int i = 1; i < AllSocketSet.fd_count; ++i)//第一个fd是监听连接的fd,第二个开始是连接上的fd
{
if (FD_ISSET(AllSocketSet.fd_array[i], &ReadFd))//通过轮询原来的集合,检查ScoketFd是否在ReadFd集合中
{
printf("接收一个连接:%s \n", inet_ntoa(ClientAddr.sin_addr));
//接收数据
ret = recv(AllSocketSet.fd_array[i], RevData, 1024, 0);
if (ret == SOCKET_ERROR)
{
DWORD err = WSAGetLastError();
if (err == WSAECONNRESET)// 客户端的socket没有被正常关闭,即没有调用closesocket
{
printf("Client is forced to close\n");
closesocket(AllSocketSet.fd_array[i]);
FD_CLR(AllSocketSet.fd_array[i], &AllSocketSet);//把AllSocketSet.fd_array[i]从AllSocketSet集合中删除
break;
}
else
{
printf("recv fail\n");
}
}
else if (ret == 0)//客户端的socket正常关闭
{
closesocket(AllSocketSet.fd_array[i]);
FD_CLR(AllSocketSet.fd_array[i], &AllSocketSet);
printf("Client closes normally");
}
else
{
printf("%s\n", RevData);//打印读取的数据
}
}
if (FD_ISSET(AllSocketSet.fd_array[i], &WriteFd))
{
//发送数据
char * SendData = "hello,TcpClient";
send(AllSocketSet.fd_array[i], SendData, strlen(SendData), 0);
}
}
}
for (u_int j = 0; j < AllSocketSet.fd_count; ++j)
{
SOCKET socket = AllSocketSet.fd_array[j];
closesocket(socket);
}
WSACleanup();//终止 DLL 的使用
return 0;
}
|