C++开发基础之网络编程WinSock库使用详解TCP/UDP Socket开发

引言

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库的基本用法:

  1. 引入头文件

在代码文件的开头引入Winsock库的头文件。

#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
  1. 初始化Winsock库

在程序开始时,调用 WSAStartup() 函数来初始化Winsock库。该函数接受一个 WSADATA 结构体作为参数。

WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
    // 错误处理
}
  1. 创建Socket

使用 socket() 函数创建一个新的socket。该函数与标准的socket函数相似,但参数类型不同。

SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET) {
    // 错误处理
}
  1. 连接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) {
    // 错误处理
}
  1. 绑定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) {
    // 错误处理
}
  1. 监听Socket(服务端)

如果你是编写服务端程序,则需要调用 listen() 函数开始监听客户端连接请求。该函数与标准的listen函数相似,但参数类型不同。

if (listen(sockfd, 5) == SOCKET_ERROR) {
    // 错误处理
}
  1. 接受连接请求(服务端)

使用 accept() 函数接受客户端的连接请求,并返回一个新的socket文件描述符,用于后续与客户端通信。该函数与标准的accept函数相似,但参数类型不同。

struct sockaddr_in clientAddr{};
int clientAddrLen = sizeof(clientAddr);
SOCKET clientSockfd = accept(sockfd, (struct sockaddr*)&clientAddr, &clientAddrLen);
if (clientSockfd == INVALID_SOCKET) {
    // 错误处理
}
  1. 发送和接收数据

使用 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) {
    // 错误处理
}
  1. 关闭Socket

使用 closesocket() 函数关闭socket。

closesocket(sockfd);
  1. 清理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库创建了一个套接字并将数据发送给服务器,然后等待服务器回复。最后关闭套接字并退出程序。

以上就是TCP Socket和UDP Socket的服务端和客户端示例程序。
这些程序可以作为网络编程的入门示例。

参考文档

  • 19
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Winsock是Windows Socket的缩写,是Windows操作系统提供的一组API,可以在Windows平台上实现网络编程。下面是一个简单的Winsock编程实现聊天程序的示例代码: 客户端: ```c++ #include <winsock2.h> #include <iostream> #include <string> #pragma comment(lib, "ws2_32.lib") using namespace std; int main() { WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) { cout << "WSAStartup failed: " << iResult << endl; return 1; } SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (clientSocket == INVALID_SOCKET) { cout << "Error at socket(): " << WSAGetLastError() << endl; WSACleanup(); return 1; } sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); clientService.sin_port = htons(27015); iResult = connect(clientSocket, (SOCKADDR*)&clientService, sizeof(clientService)); if (iResult == SOCKET_ERROR) { cout << "Failed to connect: " << WSAGetLastError() << endl; WSACleanup(); return 1; } // 发送消息 string message; while (getline(cin, message)) { iResult = send(clientSocket, message.c_str(), message.length(), 0); if (iResult == SOCKET_ERROR) { cout << "send failed: " << WSAGetLastError() << endl; closesocket(clientSocket); WSACleanup(); return 1; } } iResult = shutdown(clientSocket, SD_SEND); if (iResult == SOCKET_ERROR) { cout << "shutdown failed: " << WSAGetLastError() << endl; closesocket(clientSocket); WSACleanup(); return 1; } closesocket(clientSocket); WSACleanup(); return 0; } ``` 服务端: ```c++ #include <winsock2.h> #include <iostream> #include <string> #pragma comment(lib, "ws2_32.lib") using namespace std; int main() { WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) { cout << "WSAStartup failed: " << iResult << endl; return 1; } SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listenSocket == INVALID_SOCKET) { cout << "Error at socket(): " << WSAGetLastError() << endl; WSACleanup(); return 1; } sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = INADDR_ANY; service.sin_port = htons(27015); iResult = bind(listenSocket, (SOCKADDR*)&service, sizeof(service)); if (iResult == SOCKET_ERROR) { cout << "bind failed: " << WSAGetLastError() << endl; closesocket(listenSocket); WSACleanup(); return 1; } iResult = listen(listenSocket, SOMAXCONN); if (iResult == SOCKET_ERROR) { cout << "listen failed: " << WSAGetLastError() << endl; closesocket(listenSocket); WSACleanup(); return 1; } SOCKET clientSocket = accept(listenSocket, NULL, NULL); if (clientSocket == INVALID_SOCKET) { cout << "accept failed: " << WSAGetLastError() << endl; closesocket(listenSocket); WSACleanup(); return 1; } char recvbuf[512]; int recvbuflen = 512; do { iResult = recv(clientSocket, recvbuf, recvbuflen, 0); if (iResult > 0) { recvbuf[iResult] = '\0'; cout << "Received message: " << recvbuf << endl; } else if (iResult == 0) { cout << "Connection closing..." << endl; } else { cout << "recv failed: " << WSAGetLastError() << endl; closesocket(clientSocket); WSACleanup(); return 1; } } while (iResult > 0); iResult = shutdown(clientSocket, SD_SEND); if (iResult == SOCKET_ERROR) { cout << "shutdown failed: " << WSAGetLastError() << endl; closesocket(clientSocket); WSACleanup(); return 1; } closesocket(clientSocket); WSACleanup(); return 0; } ``` 这个程序只能实现客户端与服务端之间的单向通信,如果想实现双向通信,需要在服务端代码中加入发送消息的代码。 ### 回答2: WinSock编程是一种用于实现网络通信的编程技术,可以实现聊天程序。在聊天程序的实现中,需要使用两个主要的Socket函数:socket()和bind()。 首先,我们需要创建一个被动的套接字,用于接收客户端的连接。这可以通过调用socket()函数来实现。然后,我们使用bind()函数将创建的套接字绑定到一个特定的端口上,以便客户端能够与之建立连接。 接下来,我们需要使用listen()函数将套接字置于监听状态,以便等待客户端的连接请求。一旦有客户端连接进来,我们可以使用accept()函数接受连接,并为该客户端创建一个新的套接字。 然后,我们可以使用recv()和send()函数来实现服务器和客户端之间的消息交换。服务器使用recv()函数接收客户端发送的消息,而客户端使用send()函数向服务器发送消息。这样,就可以实现基本的聊天功能。 在编写程序时,需要注意处理异常情况和错误。例如,当客户端断开连接时,服务器应该能够处理该情况,并清理资源。使用try-catch语句可以捕获异常并进行适当的处理。 除了基本的聊天功能,我们还可以通过添加其他功能来提升聊天程序的体验,例如多人聊天、文件传输等。这可以通过在程序中添加额外的功能和相应的Socket函数来实现。 总之,通过使用WinSock编程,我们可以实现一个简单的聊天程序。这个程序利用Socket函数来实现服务器和客户端之间的网络通信,并通过recv()和send()函数实现消息的传输。编写聊天程序时需要注意处理异常情况和错误,以提供稳定可靠的用户体验。 ### 回答3: WinSock是一种用于在Windows操作系统上进行网络编程的API。通过使用WinSock编程,我们可以实现一个简单的聊天程序。 首先,我们需要在程序中包含WinSock的头文件和链接。然后,我们需要创建一个套接字,它将作为客户端或服务器与其他计算机通信的端点。 在客户端程序中,我们首先需要使用WSAStartup函数初始化WinSock。然后,我们可以创建一个套接字,并使用connect函数将其连接到服务器的IP地址和端口。接下来,我们可以使用send函数向服务器发送消息,使用recv函数接收服务器发送的消息。最后,我们使用closesocket函数关闭套接字。 在服务器程序中,我们首先也需要使用WSAStartup函数初始化WinSock。然后,我们可以创建一个套接字,并使用bind函数将其绑定到一个IP地址和端口。接下来,我们使用listen函数开始监听客户端连接请求。当客户端连接到服务器时,我们使用accept函数接受连接,并创建一个新的套接字来与该客户端通信。然后,我们可以使用send函数向客户端发送消息,使用recv函数接收客户端发送的消息。最后,我们使用closesocket函数关闭套接字。 通过以上步骤,我们可以实现一个简单的聊天程序。当客户端和服务器之间建立连接后,它们可以相互发送消息,实现实时通信。当然,为了更好的用户体验,我们还可以在程序中添加一些额外的功能,如界面设计、消息记录等。 总而言之,通过WinSock编程,我们可以轻松实现一个基于客户端-服务器模型的聊天程序。该程序可以让多个计算机相互通信,为用户提供便捷的沟通方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小乖兽技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值