引言
Winsock是Windows操作系统提供的用于网络编程的API库。它是Windows Sockets的简称,也就是套接字库。Winsock可以让开发人员使用TCP/IP协议族中的各种协议,如TCP、UDP等,在Windows平台下进行网络编程。
Winsock提供了一组函数和数据结构,这些函数和数据结构可以让开发人员创建和管理套接字(Socket),并通过套接字与其他计算机进行通信。套接字是一种抽象的通信端点,通过套接字可以进行不同计算机之间的数据传输。Winsock提供了一些基本的套接字函数,如socket()、bind()、connect()、send()、recv()等,这些函数实现了套接字的创建、绑定、连接、发送数据和接收数据等操作。
Winsock还提供了对异步IO(Asynchronous IO)的支持,这使得在网络编程中能够使用异步IO模型来处理事件。此外,Winsock还提供了对多线程编程的支持,这使得开发人员能够在网络编程中使用异步IO和多线程进行事件处理。
基本用法
以下是Winsock库的基本用法:
- 引入头文件
在代码文件的开头引入Winsock库的头文件。
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
- 初始化Winsock库
在程序开始时,调用 WSAStartup()
函数来初始化Winsock库。该函数接受一个 WSADATA
结构体作为参数。
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
// 错误处理
}
- 创建Socket
使用 socket()
函数创建一个新的socket。该函数与标准的socket函数相似,但参数类型不同。
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET) {
// 错误处理
}
- 连接Socket(客户端)
如果你是编写客户端程序,则需要调用 connect()
函数连接到服务端。该函数与标准的connect函数相似,但参数类型不同。
struct sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080); // 服务端的端口号,要使用网络字节序
if (inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr) <= 0) {
// 错误处理
}
if (connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
// 错误处理
}
- 绑定Socket(服务端)
如果你是编写服务端程序,则需要调用 bind()
函数将socket与一个IP地址和端口绑定起来。该函数与标准的bind函数相似,但参数类型不同。
struct sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080); // 端口号,要使用网络字节序
serverAddr.sin_addr.s_addr = INADDR_ANY; // IP地址,INADDR_ANY表示任意地址
if (bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
// 错误处理
}
- 监听Socket(服务端)
如果你是编写服务端程序,则需要调用 listen()
函数开始监听客户端连接请求。该函数与标准的listen函数相似,但参数类型不同。
if (listen(sockfd, 5) == SOCKET_ERROR) {
// 错误处理
}
- 接受连接请求(服务端)
使用 accept()
函数接受客户端的连接请求,并返回一个新的socket文件描述符,用于后续与客户端通信。该函数与标准的accept函数相似,但参数类型不同。
struct sockaddr_in clientAddr{};
int clientAddrLen = sizeof(clientAddr);
SOCKET clientSockfd = accept(sockfd, (struct sockaddr*)&clientAddr, &clientAddrLen);
if (clientSockfd == INVALID_SOCKET) {
// 错误处理
}
- 发送和接收数据
使用 send()
函数发送数据,使用 recv()
函数接收数据。这两个函数与标准的send和recv函数相似,但参数类型不同。
const char* message = "Hello, server!";
if (send(sockfd, message, strlen(message), 0) == SOCKET_ERROR) {
// 错误处理
}
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
if (recv(sockfd, buffer, sizeof(buffer), 0) == SOCKET_ERROR) {
// 错误处理
}
- 关闭Socket
使用 closesocket()
函数关闭socket。
closesocket(sockfd);
- 清理Winsock库
在程序结束时,调用 WSACleanup()
函数来清理Winsock库。
WSACleanup();
以上是Winsock库的基本用法。注意,在使用Winsock库前要先初始化库,并在使用完后进行清理。
TCP Socket 示例
1.TCP Socket 服务端代码示例:
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET)
{
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = INADDR_ANY;
service.sin_port = htons(27015);
if (bind(ListenSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR)
{
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf("Server is running and waiting to accept a client connection...\n");
SOCKET ClientSocket = INVALID_SOCKET;
while (ClientSocket == INVALID_SOCKET)
{
ClientSocket = accept(ListenSocket, NULL, NULL);
}
printf("Client connected!\n");
char recvbuf[512];
int iRecvResult;
do
{
iRecvResult = recv(ClientSocket, recvbuf, sizeof(recvbuf), 0);
if (iRecvResult > 0)
{
printf("Bytes received: %d\n", iRecvResult);
printf("Received data: %s\n", recvbuf);
send(ClientSocket, recvbuf, iRecvResult, 0);
}
else if (iRecvResult == 0)
{
printf("Connection closing...\n");
}
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iRecvResult > 0);
closesocket(ClientSocket);
WSACleanup();
return 0;
}
上述代码实现了一个TCP Socket的服务端程序。该程序使用Winsock库创建了一个监听套接字,端口号为27015,等待客户端连接。一旦有客户端连接,就会创建一个新的套接字来处理客户端请求,然后通过该套接字与客户端进行通信。
2.TCP Socket 客户端代码示例:
#include <stdio.h>
#include <winsock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
SOCKET ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
{
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
sockaddr_in service;
service.sin_family = AF_INET;
//service.sin_addr.s_addr = inet_addr("127.0.0.1");
inet_pton(AF_INET, "127.0.0.1", &service.sin_addr.s_addr);
service.sin_port = htons(27015);
if (connect(ConnectSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR)
{
printf("connect failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Connected to server!\n");
char sendbuf[512] = "Hello from client!";
int iSendResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
char recvbuf[512];
int iRecvResult = recv(ConnectSocket, recvbuf, sizeof(recvbuf), 0);
if (iRecvResult > 0)
{
printf("Bytes received: %d\n", iRecvResult);
printf("Received data: %s\n", recvbuf);
}
else if (iRecvResult == 0)
{
printf("Connection closed by server.\n");
}
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
}
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
上述代码实现了一个TCP Socket的客户端程序。该程序使用Winsock库创建了一个套接字并连接到服务器,然后发送一条消息给服务器,并等待服务器回复。最后关闭套接字并退出程序。
UDP Socket示例
1.UDP Socket 服务端代码示例:
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
SOCKET ListenSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ListenSocket == INVALID_SOCKET)
{
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = INADDR_ANY;
service.sin_port = htons(27015);
if (bind(ListenSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf("Server is running and waiting to receive data...\n");
char recvbuf[512];
int iRecvResult;
sockaddr_in clientAddr;
int iAddrLen = sizeof(clientAddr);
do
{
iRecvResult = recvfrom(ListenSocket, recvbuf, sizeof(recvbuf), 0, (SOCKADDR*)&clientAddr, &iAddrLen);
if (iRecvResult > 0)
{
printf("Bytes received: %d\n", iRecvResult);
printf("Received data: %s\n", recvbuf);
sendto(ListenSocket, recvbuf, iRecvResult, 0, (SOCKADDR*)&clientAddr, sizeof(clientAddr));
}
else if (iRecvResult == 0)
{
printf("Connection closing...\n");
}
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
} while (iRecvResult > 0);
closesocket(ListenSocket);
WSACleanup();
return 0;
}
上述代码实现了一个UDP Socket的服务端程序。该程序使用Winsock库创建了一个监听套接字,端口号为27015,等待客户端发送数据。一旦有客户端发送数据,就会通过该套接字接收数据,并将接收到的数据原封不动地发送回去。
2.UDP Socket 客户端代码示例:
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
SOCKET ConnectSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ConnectSocket == INVALID_SOCKET)
{
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
sockaddr_in service;
service.sin_family = AF_INET;
//service.sin_addr.s_addr = inet_addr("127.0.0.1");
inet_pton(AF_INET, "127.0.0.1", &service.sin_addr.s_addr);
service.sin_port = htons(27015);
char sendbuf[512] = "Hello from client!";
int iSendResult = sendto(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0, (SOCKADDR*)&service, sizeof(service));
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
char recvbuf[512];
int iRecvResult;
int iAddrLen = sizeof(service);
iRecvResult = recvfrom(ConnectSocket, recvbuf, sizeof(recvbuf), 0, (SOCKADDR*)&service, &iAddrLen);
if (iRecvResult > 0)
{
printf("Bytes received: %d\n", iRecvResult);
printf("Received data: %s\n", recvbuf);
}
else if (iRecvResult == 0)
{
printf("Connection closed by server.\n");
}
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
}
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
上述代码实现了一个UDP Socket的客户端程序。该程序使用Winsock库创建了一个套接字并将数据发送给服务器,然后等待服务器回复。最后关闭套接字并退出程序。文章来源:https://www.toymoban.com/news/detail-818996.html
以上就是TCP Socket和UDP Socket的服务端和客户端示例程序。
这些程序可以作为网络编程的入门示例。文章来源地址https://www.toymoban.com/news/detail-818996.html
参考文档
- TCP和UDP协议的区别以及原理
- Windows 环境下的 Socket 编程 1 - 环境搭建和 Socket 相关函数
- Windows Socket介绍
- 解决“‘inet_addr‘: Use inet_pton() or InetPton() instead “问题
- C4996: ‘inet_addr‘: Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS
到了这里,关于C++开发基础之网络编程WinSock库使用详解TCP/UDP Socket开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!