实际 windows 下 socket 编程和 linux 下几乎没有什么区别,函数名、结构体信息等都一模一样的,因为这些并非是操作系统所设计决定的。而是由公共的组织在维护和约定这些规范。在 windows 下唯一与 linux 不同的就是需要自己手动加载套接字库。其他几乎完全一致,参考以下代码。
TCP 程序服务端/客户端代码
#include <Winsock2.h> #include <iostream> using namespace std; #pragma comment(lib,"Ws2_32.lib") int main(int argc, char* argv[]) { WSADATA wsaData; WORD wVersion = MAKEWORD(2, 2); // 加载socket库 int wsaResult = WSAStartup(wVersion, &wsaData); if (wsaResult != 0) { return -1; } // 判断加载的库是否是正确的版本 if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { WSACleanup(); return -2; } // 创建 socket 连接 SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in srvaddr; srvaddr.sin_family = AF_INET; srvaddr.sin_addr.S_un.S_addr = htonl(ADDR_ANY); srvaddr.sin_port = htons(8000); // 绑定服务器的IP和端口 bind(sock, (sockaddr*)&srvaddr, sizeof(srvaddr)); // 监听 listen(sock, 20); sockaddr_in cntaddr; int len = sizeof(cntaddr); char recvBuf[512]; while (1) { // 等待客户端连接 SOCKET conn = accept(sock, (sockaddr*)&cntaddr, &len); // 有链接后接收数据 int ret = recv(conn, recvBuf, sizeof(recvBuf), 0); cout << "recv data : " << ret << recvBuf << endl; } // 关闭 socket closesocket(sock); WSACleanup(); return 0; }
客户端代码
#include <WinSock2.h> #include <Ws2tcpip.h> #include <iostream> using namespace std; #pragma comment(lib,"Ws2_32.lib") int main(int argc, char* argv[]) { // 加载套接字库 WSADATA wsaData; WORD wVersion = MAKEWORD(2, 2); int wsaResult = WSAStartup(wVersion, &wsaData); if (wsaResult != 0) { return -1; } // 判断加载的库版本是否正确 if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { WSACleanup(); return -2; } // 创建 socket SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); // 构建服务端信息并连接 sockaddr_in srvaddr; srvaddr.sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &(srvaddr.sin_addr)); srvaddr.sin_port = htons(8000); connect(sock, (sockaddr*)&srvaddr, sizeof(srvaddr)); // 向服务端发送数据 char sendBuf[] = "Windows Socket 通信测试程序"; send(sock, sendBuf, sizeof(sendBuf), 0); // 关闭套接字 closesocket(sock); // 销毁套接字库 WSACleanup(); return 0; }
创建 win32 控制台应用程序的空项目,将以上代码复制到你的 cpp 中就可以直接编译运行了,代码中客户端会连接服务端发送一句 “Windows Socket 通信测试程序”。
UDP 程序服务端/客户端代码
#include <WinSock2.h>
#include <Ws2tcpip.h>
#include <iostream>
using namespace std;
#pragma comment(lib,"Ws2_32.lib")
int main(int argc, char* argv[])
{
// 加载套接字库
WORD wVersion = MAKEWORD(2, 2);
WSAData wsData;
WSAStartup(wVersion, &wsData);
// 创建套接字
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
// 绑定本地IP和端口
sockaddr_in srvaddr;
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);
srvaddr.sin_port = htons(8000);
bind(sock, (sockaddr*)&srvaddr, sizeof(srvaddr));
// 预分配各种内存,然后循环接收客户端数据
sockaddr_in cntaddr;
int len = sizeof(cntaddr);
char recvBuf[1024];
char szAddress[16];
while (1)
{
// 接收数据并把客户端信息存放到 cntaddr 结构体中
recvfrom(sock, recvBuf, sizeof(recvBuf), 0, (sockaddr*)&cntaddr, &len);
// 将结构体中的IP信息转换存放到char数组中
inet_ntop(AF_INET, &(cntaddr.sin_addr.S_un.S_addr), szAddress, sizeof(szAddress));
// 打印客户端ip和发送过来的消息
cout << szAddress << " : " << recvBuf << endl;
}
// 关闭套接字
closesocket(sock);
// 卸载套接字库
WSACleanup();
return 0;
}
客户端代码
#include <WinSock2.h> #include <Ws2tcpip.h> #include <iostream> using namespace std; #pragma comment(lib,"Ws2_32.lib") int main(int argc, char* argv[]) { // 加载套接字库 WORD wVersion = MAKEWORD(2, 2); WSAData wsData; WSAStartup(wVersion, &wsData); // 创建套接字 SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); // 构建服务器信息直接向服务器发送数据,不像TCP无需connect sockaddr_in srvaddr; srvaddr.sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &(srvaddr.sin_addr.S_un.S_addr)); srvaddr.sin_port = htons(8000); char sendBuf[] = "hello server"; sendto(sock, sendBuf, sizeof(sendBuf), 0, (sockaddr*)&srvaddr, sizeof(srvaddr)); // 关闭套接字 closesocket(sock); // 卸载套接字库 WSACleanup(); return 0; }
同样适用 win32 控制台应用程序空项目编译即可运行。