TCP 是面向有连接的可靠传输协议,来讲讲它的一个 Windows 的基本实现。

学习笔记

首先在 Windows 下 socket 编程要添加这样的预处理:

1
2
# include<WinSock2.h>
# pragma comment(lib,"ws2_32.lib")

然后我们需要启动一下,一般加入以下代码即可:

1
2
3
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA lpWSAData;
int nRet = WSAStartup(wVersionRequested, &lpWSAData);

为了程序健壮可以添加一些判断代码。

1
2
3
4
5
6
7
8
9
10
if (nRet != 0) {
printf("WSAStartup Error!\n");
system("pause");
return 0;
}
if (LOBYTE(lpWSAData.wVersion) != 2 || HIBYTE(lpWSAData.wVersion) != 2) {
WSACleanup();
printf("wVersion Error\n");
return 0;
}

然后就到了我们最关键的一步了。

建立服务端

创建套接字连接对象

我们先要起一个连接对象,也就是 SOCKET 对象,然后用 socket 方法去创建,socket 方法有三个参数,第一个参数为协议簇,第二个参数为 socket 类型,第三个参数为标志位。

第一个参数就给 AF_INET 表示 IPv4 网络协议的套接字类型,第二个参数给 SOCK_STREAM 表示为流套接字,第三个参数直接给 0 好了。

创建套接字对象

这个对象名为 SOCKADDR_IN。里面有一些成员需要我们设置,我们只需要考虑三个信息:协议簇,绑定在哪个 ip,绑定在哪个端口。

这里我们直接

1
2
3
4
SOCKADDR_IN addServer;
addServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addServer.sin_family = AF_INET;
addServer.sin_port = htons(9999);

就把它设置了本地的 9999 端口。

监听端口

1
2
3
int len = sizeof(addServer);
bind(SockServer, (sockaddr*)&addServer, len);
listen(SockServer,5);

然后使用 bind 方法去绑定套接字,最后用 listen 方法去监听端口,到这里服务端就完成了。

当然呢连接过来的时候,我们需要给客户端建立一个连接对象,然后对这个对象进行操作就相当于发送数据了,我们发送接收数据使用 send 和 recv 方法。

为了防止 socket 只运行一遍就关闭我们可以 while 1 去处理请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char msg[] = "Hello,You successfully login!!\n";
char msg1[] = "I will repeat your message Once\n";
while (1) {
SOCKET sockConn = accept(SockServer, (sockaddr*)&addrClient, &len);
send(sockConn, msg, strlen(msg), 0);
char buffer[MAX_PATH];
char SendBuffer[MAX_PATH];
memset(buffer, 0, sizeof(buffer));
memset(SendBuffer, 0, sizeof(SendBuffer));
recv(sockConn, buffer, MAX_PATH, 0);
sprintf(SendBuffer, buffer);

printf("%s", buffer);

send(sockConn, msg1, strlen(msg1), 0);
send(sockConn, SendBuffer, strlen(SendBuffer), 0);
}

最终代码

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
# include<stdio.h>
# include<WinSock2.h>
# pragma comment(lib,"ws2_32.lib")
int main() {
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA lpWSAData;
int nRet = WSAStartup(wVersionRequested, &lpWSAData);
/*if (nRet != 0) {
printf("WSAStartup Error!\n");
system("pause");
return 0;
}
if (LOBYTE(lpWSAData.wVersion) != 2 || HIBYTE(lpWSAData.wVersion) != 2) {
WSACleanup();
printf("wVersion Error\n");
return 0;
}*/
SOCKET SockServer = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addServer;
addServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addServer.sin_family = AF_INET;
addServer.sin_port = htons(9999);
int len = sizeof(addServer);
bind(SockServer, (sockaddr*)&addServer, len);
listen(SockServer,5);
SOCKADDR_IN addrClient;
char msg[] = "Hello,You successfully login!!\n";
char msg1[] = "I will repeat your message Once\n";
while (1) {
SOCKET sockConn = accept(SockServer, (sockaddr*)&addrClient, &len);
send(sockConn, msg, strlen(msg), 0);
char buffer[MAX_PATH];
char SendBuffer[MAX_PATH];
memset(buffer, 0, sizeof(buffer));
memset(SendBuffer, 0, sizeof(SendBuffer));
recv(sockConn, buffer, MAX_PATH, 0);
sprintf(SendBuffer, buffer);

printf("%s", buffer);

send(sockConn, msg1, strlen(msg1), 0);
send(sockConn, SendBuffer, strlen(SendBuffer), 0);
}
}

最后使用 nc 去连接看看效果。

服务端运行结果: