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

这篇具有很好参考价值的文章主要介绍了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的服务端和客户端示例程序。
这些程序可以作为网络编程的入门示例。文章来源地址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模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++网络编程 TCP套接字基础知识,利用TCP套接字实现客户端-服务端通信

    流式套接字编程针对TCP协议通信,即是面向对象的通信,分为服务端和客户端两部分。 1)加载套接字库( 使用函数WSAStartup() ),创建套接字( 使用socket() ) 2)绑定套接字到一个IP地址和一个端口上( 使用函数bind() ) 3)将套接字设置为监听模式等待连接请求( 使用函数

    2024年02月03日
    浏览(42)
  • 【100天精通python】Day47:python网络编程_Web开发:web服务器,前端基础以及静态服务器

    目录 1  网络编程与web编程 1.1 网络编程 1.2 web编程  1.3 前后端交互的基本原理/

    2024年02月11日
    浏览(43)
  • 树莓派Pico W无线WiFi开发板使用方法及MicroPython网络编程实践

    树莓派Pico W开发板是树莓派基金会于2022年6月底推出的一款无线WiFi开发板,它支持C/C++和MicroPython编程。本文介绍树莓派Pico W无线WiFi开发板的使用方法及MicroPython编程示例,包括树莓派Pico W开发板板载LED使用及控制编程示例,Pico W开发板用作WiFi无线HTTP网络服务器的MicroPython编

    2023年04月12日
    浏览(39)
  • 【Java基础教程】(四十七)网络编程篇:网络通讯概念,TCP、UDP协议,Socket与ServerSocket类使用实践与应用场景~

    了解多线程与网络编程的操作关系; 了解网络程序开发的主要模式; 了解 TCP 程序的基本实现; 在Java中,网络编程的核心意义是实现不同电脑主机之间的数据交互。Java采用了一种简化的概念,将这个过程进一步抽象为JVM(Java虚拟机)进程之间的通信。可以在同一台电脑上

    2024年02月15日
    浏览(42)
  • 【C++】6.网络编程:网络编程(TCP&UDP)

    网络编程是C++ API操作中很重要的一部分,包含 TCP 和 UDP 。 网络传输模型可以抽象为7个层: 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层 。 但在使用TCP/IP协议时,可以简化为这4层: 网络接口、网络层、传输层、应用层 。 TCP:可靠传输,三次握手建立

    2024年02月16日
    浏览(33)
  • [C++ 网络协议编程] 域名及网络地址

    DNS(Domain Name System):是对IP地址和域名(如:www.baidu.com等)进行相互转换的系统,其核心是DNS服务器。 我们输入的www.baidu.com是域名,是一种虚拟地址,而非实际地址,DNS服务器会将这个虚拟地址转换为实际地址,即IP地址。若我们直接输入IP地址,则不会发生上面的转换。

    2024年02月12日
    浏览(35)
  • 【网络编程】网络基础

    需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。   目录 一、协议分层 1、为什么要分层 2、OSI七层模型 3、TCP/IP四层协议(五层协议) 二、网络传输流程 1、同一个网段内的两

    2024年02月02日
    浏览(37)
  • 【网络编程】Linux网络编程基础与实战第三弹——网络名词术语

    数据包从源地址到目的地址所经过的路径,由一系列路由节点组成。 某个路由节点为数据包选择投递方向的选路过程。 路由器工作原理 路由器是连接因特网中各局域网、广域网的设备,它会根据信道的情况自动选择和设定路由,以最佳路径,按前后顺序发送信号的设备。

    2024年02月08日
    浏览(39)
  • Linux网络编程:网络基础

    文章目录: 一:协议   二:网络应用设计模式_BS模式和CS模式 三:网络分层模型(OSI七层 TCP/IP四层) 四:通信过程 五:协议格式  1.数据包封装 2.以太网帧格式和ARP数据报格式  3.IP段格式  4.UDP数据报格式 5.TCP数据报格式 六:TCP协议 1.TCP通信时序(面向连接的可靠数据通

    2024年02月12日
    浏览(74)
  • 网络编程 p1 网络基础

    概念:两台设备之间通过网络实现数据传输; 网络通信:将数据通过网络从一台设备传输到另一台设备; java.net包下提供了一系列的类或接口,供程序员使用,完成网络通信; 概念:两台或多台设备通过一定物理设备连接起来构成了网络; 根据网络的覆盖范围不同,对网络

    2024年02月16日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包