实际 windows 下 socket 编程和 linux 下几乎没有什么区别,函数名、结构体信息等都一模一样的,因为这些并非是操作系统所设计决定的。而是由公共的组织在维护和约定这些规范。在 windows 下唯一与 linux 不同的就是需要自己手动加载套接字库。其他几乎完全一致,参考以下代码。


TCP 程序服务端/客户端代码

#include <Winsock2.h>
#include

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

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 程序服务端/客户端代码

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
#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

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 控制台应用程序空项目编译即可运行。