Win32 Socket 使用

库说明

Win32 进行网络编程需要使用到 ws2_32.lib 库,它是 Windows Sockets 2 (Winsock2) 的库文件,其主要头文件为winsock2.h。如果使用 Windows.h 头文件则默认包含 winsock.h,他会和 winsock2.h 冲突。可以通过在包含 Windows.h 之前定义宏 WIN32_LEAN_AND_MEAN 来排除一些不常用的 Windows 头文件,这里面就会排除掉 winsock.h

// 链接 Winsock 库
#pragma comment(lib, "WS2_32.lib") 

//排除掉 Windows.h 中包含的一些不常用头文件
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>

常用API

API说明参数
WSAStartup初始化WinSock库wVersionRequired:版本号,MAKEWORD(2, 2)表示2.2版本
lpWSAData:存储关于 Winsock 的信息
WSACleanup清理WinSock库
socket创建一个socketdomain:指定socket使用的地址族(AF_INET、AF_INET6等)
type:socket类型SOCK_STREAM(TCP)、SOCK_DGRAM(UDP)等
protocol:使用的协议IPPROTO_TCP、IPPROTO_UDP,0表示自动选择
返回值:socket的文件描述符号
bind将socket与一个特定的地址和端口绑定sockfd:socket文件描述符
addr:包含地址信息的结构体的指针
addrlen:addr结构体长度
返回值:成功时返回 0,失败时返回 SOCKET_ERROR
listen将socket转换为监听状态sockfd:socket文件描述符
backlog:等待接受连接的客户端的最大数量,超过将被拒绝
accept接受客户端的连接请求,并创建一个新的套接字用于与客户端进行通信sockfd:socket文件描述符
addr:输出参数,用于纪录客户端的地址
addrlen:输出参数,表示addr的实际长度
返回值:返回一个新的套接字文件描述符,如果出现错误返回 SOCKET_ERROR
connect请求连接服务器s:标识要连接的 socket
name:服务器的地址信息
namelen:服务器地址信息结构体大小
send发送内容到sockets:socket文件描述符
buf:发送数据的缓冲区
len:需要发送字节数
flags:控制接收操作的行为,通常为 0
返回值:返回发送的字节数。如果出现错误,返回 SOCKET_ERROR
recv从已连接的socket接收数据sockfd:socket文件描述符
buf:接收数据的缓冲区
len:缓冲区大小,可以接收最大字节数
flags:控制接收操作的行为,通常为 0
返回值:返回接收的字节数。如果连接已关闭,返回 0。如果出现错误,返回 SOCKET_ERROR
closesocket关闭socket
inet_pton将点分十进制的IP转换为Long
它不是标准 Winsock 函数
它是在高版本中定义的
需要引用 Ws2tcpip.h 头文件
af:地址族(AF_INET、AF_INET6)
src:点分十进制字符串指针
转换后的二进制地址
inet_ntop将Long类型的IP转换为点分十进制
htons将16位主机字节序转换为网络字节序
网络字节序都采用大端字节序
用于端口号转换
htonl将32位主机字节序转换为网络字节序
网络字节序都采用大端字节序
用于IP转换

服务端

static DWORD WINAPI serverRecv(LPVOID lpParameter) {
	int* clientSocket = (int*)lpParameter;
	char readBuffer[512];
	while (true) {
		memset(readBuffer, 0, 512);
		int readSize = recv(*clientSocket, readBuffer, 512, 0);
		if (readSize <= 0) {
			perror("recv");
			closesocket(*clientSocket);
			return 0;
		}
		printf("read buffer = %s", readBuffer);
	}

	return 0;
}

static DWORD WINAPI server(LPVOID lpParameter) {
	// 初始化 Winsock 2.2 版本
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		printf("Failed to initialize Winsock\n");
	}

	int serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (serverSocket == INVALID_SOCKET) {
		perror("socket");
	}

	sockaddr_in serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.S_un.S_addr = INADDR_ANY;
	serverAddr.sin_port = htons(12345);
	if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
		perror("bind");
	}

	if (listen(serverSocket, SOMAXCONN) == -1) {
		perror("listen");
	}

	while (TRUE) {
		sockaddr_in clientAddr;
		int* addrlen = NULL;
		int clientSocket = accept(serverSocket, (struct sockaddr*)&serverAddr, addrlen);
		if (clientSocket == -1) {
			perror("accept");
			continue;
		}

		CreateThread(NULL, 0, serverRecv, &clientSocket, 0, NULL);
	}

	return 0;
}

客户端

static DWORD WINAPI client(LPVOID lpParameter) {
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		printf("Failed to initialize Winsock\n");
	}

	printf("create client socket \n");
	int clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (clientSocket == INVALID_SOCKET) {
		perror("socket");
	}

	sockaddr_in serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(12345);
	inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
	
	if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
		fprintf(stderr, "Failed to connect to server\n");
	}

	const char* message = "Hello, Server!";
	if (send(clientSocket, message, strlen(message), 0) == SOCKET_ERROR) {
		fprintf(stderr, "Failed to send data to server\n");
	}else {
		printf("Data sent to server: %s\n", message);
	}

	return 0;
}
  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用WinSock库封装的简单Win32 Socket服务端类的示例: ```cpp #include <iostream> #include <string> #include <WinSock2.h> #pragma comment(lib, "ws2_32.lib") class SocketServer { public: SocketServer(int port) : serverPort(port), serverSocket(INVALID_SOCKET) { if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { std::cerr << "Failed to initialize WinSock" << std::endl; throw; } serverSocket = socket(AF_INET, SOCK_STREAM, 0); if (serverSocket == INVALID_SOCKET) { std::cerr << "Failed to create socket" << std::endl; WSACleanup(); throw; } serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(serverPort); if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { std::cerr << "Bind failed with error" << WSAGetLastError() << std::endl; closesocket(serverSocket); WSACleanup(); throw; } if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) { std::cerr << "Listen failed with error" << WSAGetLastError() << std::endl; closesocket(serverSocket); WSACleanup(); throw; } } ~SocketServer() { closesocket(serverSocket); WSACleanup(); } void startListening() { struct sockaddr_in clientAddr; int clientAddrLen = sizeof(clientAddr); while (true) { SOCKET clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen); if (clientSocket == INVALID_SOCKET) { std::cerr << "Accept failed with error" << WSAGetLastError() << std::endl; closesocket(serverSocket); WSACleanup(); return; } std::cout << "Client connected" << std::endl; // 处理客户端请求 std::string response = "Hello, client!"; send(clientSocket, response.c_str(), response.length(), 0); // 关闭客户端连接 closesocket(clientSocket); std::cout << "Client disconnected" << std::endl; } } private: int serverPort; WSADATA wsaData; SOCKET serverSocket; SOCKADDR_IN serverAddr; }; int main() { SocketServer server(8080); server.startListening(); return 0; } ``` 这个示例演示了一个简单的Win32 Socket服务端类。它在构造函数中初始化WinSock库,创建套接字并绑定到指定的端口。然后,在`startListening`方法中,它会接受客户端连接,处理客户端请求,并发送响应。每个客户端连接完成后,套接字会被关闭。你可以根据需要扩展该类以满足特定的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值