编程思路
第一步
创建一个WASDATA结构体变量,用于存储关于Winsock库的信息;初始化Winsock库。
第二步
创建TCP套接字。
第三步
创建sockaddr_in结构体变量,用于储存服务器地址信息。里面包括设置地址族、IP地址、端口号。
第四步
调用connect函数连接服务器。
通信
调send函数发送数据
调recv函数接收数据
实现代码
头文件部分
1 2 3 4 5
| #include <iostream> #include <winsock2.h> #include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
|
main 函数部分
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
| int main() { WSADATA wsaData; int result = WSAStartup(MAKEWORD(2, 2), &wsaData); if (result != 0) { std::cout << "WSAStartup failed: " << result << std::endl; return 1; }
SOCKET connectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connectSocket == INVALID_SOCKET) { std::cout << "socket failed with error: " << WSAGetLastError() << std::endl; WSACleanup(); return 1; }
sockaddr_in service; service.sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &service.sin_addr); service.sin_port = htons(6666);
result = connect(connectSocket, (SOCKADDR*)&service, sizeof(service)); if (result == SOCKET_ERROR) { std::cout << "connect failed with error: " << WSAGetLastError() << std::endl; closesocket(connectSocket); WSACleanup(); return 1; }
std::cout << "Connected to server." << std::endl;
char sendBuffer[1024] = "Hello, server!"; result = send(connectSocket, sendBuffer, sizeof(sendBuffer), 0); if (result == SOCKET_ERROR) { std::cout << "send failed with error: " << WSAGetLastError() << std::endl; closesocket(connectSocket); WSACleanup(); return 1; }
char recvBuffer[1024]; result = recv(connectSocket, recvBuffer, sizeof(recvBuffer), 0); if (result == SOCKET_ERROR) { std::cout << "recv failed with error: " << WSAGetLastError() << std::endl; closesocket(connectSocket); WSACleanup(); return 1; }
std::cout << "Received message from server: " << recvBuffer << std::endl;
closesocket(connectSocket); WSACleanup();
return 0; }
|
注意事项(debug过程)
运行代码之前要使用网络调试助手打开TCP服务端,注意端口号、IP地址这些要匹配。
代码主要是C语言,C++部分是控制台输入输出的,如果纯C语言就include<stdio.h>,用printf、scanf这些库函数替换就好了。
以上代码使用VS的编译器上是可以直接运行的,但是如果是使用MinGW gcc/g++就会出现问题。我们来看报错。

1.inet_pton函数未定义。
inet_pton函数将点分十进制串转换成网络字节序二进制值,此函数对IPv4地址和IPv6地址都能处理,在Windows下只需包含ws2tcpip.h头文件就行了
根据网上的说法,是因为Windows gcc 默认的 _WIN32_WINNT 是 502 Windows Server 2003,所以解决方案是重新定义_WIN32_WINNT,在ws2tcpip.h前加入
1 2 3 4
| #ifdef _WIN32_WINNT #undef _WIN32_WINNT #define _WIN32_WINNT 0x0600 #endif
|
还有一个方法,那就是。。。不用inet_pton()函数了,用别的IP地址转换函数——inet_addr()
这样第三步的代码改为
1 2 3 4
| sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); service.sin_port = htons(6666);
|
这个问题就解决了。
2. 链接动态库问题undefined reference to __imp_WSAStartup
在vs中直接加入
1
| #pragma comment(lib, "ws2_32.lib")
|
就可以链接winsock动态库,不知道为什么gcc编译器不行。1 问题解决后,报如下错误:

所以在vscode的配置tasks.json的args参数加一个:"-lwsock32",在编译命令中指定链接就可以了。
对于如果找不到_imp_inet_pton的话,就需要再加args参数:"-lws2_32"。
然后就能连上TCP服务器了。

Windows下使用C++\winsock库实现tcp客户端通信