当前位置: 首页 > news >正文

天河做网站技术太原网站制作好吗

天河做网站技术,太原网站制作好吗,有没有专做于投融资的网站,wordpress七牛代码目录 一.什么是Socket套接字#xff1f; 二.Socket的使用#xff1a; 前置步骤#xff1a; 为什么要加入 WSAStartup 和 WSACleanup #xff1f; 1.创建Socket#xff1a; 2.绑定Socket#xff1a; 3.服务端监听连接请求#xff1a; 4.服务端接受客户端连接 二.Socket的使用 前置步骤 为什么要加入 WSAStartup 和 WSACleanup 1.创建Socket 2.绑定Socket 3.服务端监听连接请求 4.服务端接受客户端连接 5.客户端连接服务端 6.数据传输 1recv的使用 2send的使用 7.关闭Socket 8.案例分析 三.TCP协议流程 四.UDP协议流程 前置知识 UDP 的特性  UDP的使用 接收和发送数据的函数 recvfrom() 函数 sendto() 函数 1.UDP的服务端 2.UDP的客户端 五.前置基础知识总结 1. 网络基础知识 2. Socket 的基本概念 3. Socket 编程中的常用 API 创建和管理 Socket 发送和接收数据 地址结构和网络信息 4. 常见的 Socket 编程模式 客户端-服务器模式 广播和多播 5. 网络调试和错误处理  下面是写博客时参考总结的博客地址 1.从零开始的C网络编程-腾讯云开发者社区-腾讯云 2.C高性能网络编程 | Jack Huangs Blog 3.C/C网络编程基础知识超详细讲解第一部分系统性学习day11-阿里云开发者社区 一.什么是Socket套接字 Socket 是一种用于计算机之间网络通信的端点。它允许两个程序通过网络交换数据。Socket编程主要用于客户端和服务器的通信一般可以使用两种协议 TCP (Transmission Control Protocol)可靠、面向连接的协议适合需要完整传输的数据。TCP 是面向连接的协议通信前需要通过三次握手3-way handshake建立连接。保证数据的可靠性数据包丢失时会自动重传。通过滑动窗口等技术进行流量控制避免网络拥塞。TCP 保证数据按顺序到达。UDP (User Datagram Protocol)不可靠、无连接的协议适合对速度要求高、允许丢包的数据传输。UDP 是无连接的不需要建立连接数据可以直接发送。不保证数据的可靠送达也不保证数据顺序。由于没有建立连接的开销UDP 相比 TCP 更加高效适合实时应用。 创建 socket 的时候需要指定 socket 的类型一般有三种 SOCK_STREAM面向连接的稳定通信底层是 TCP 协议我们会一直使用这个。SOCK_DGRAM无连接的通信底层是 UDP 协议需要上层的协议来保证可靠性。SOCK_RAW更加灵活的数据控制能让你指定 IP 头部 想了解前置知识可以跳转五 -- 二.Socket的使用 下面我们基于TCP协议来详细讲述Socket的使用。  我们在编写C程序运行后代表的是服务端浏览器则是客户端首先创建一个套接字(socket())绑定(bind())到本地的IP地址和端口然后进入监听(listen())状态服务端接受(accept())客户端客户端连接(connect)服务端。连接(connect)成功后可以接收(recv)客户端数据和发送(send)数据给客户端。通信完成后关闭(close())Socket释放资源。 前置步骤 我们在 Windows 平台上使用 Winsock 编程即使用 Socket 进行网络通信时必须初始化 Winsock 库并在使用结束后清理它。  #include iostream #include string.h #include WinSock2.h // 声明了所有与 Windows 套接字Socket相关的函数和数据结构。WSADATA 结构体以及 WSAStartup、WSACleanup 函数也在此头文件中定义。 #pragma comment(lib,ws2_32.lib) using namespace std; int main() {// 初始化 Winsock 库WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), wsaData) ! 0) {cerr WSAStartup failed: WSAGetLastError() endl;return -1;}//socket流程...// 释放Winsock的资源WSACleanup(); } MAKEWORD(2, 2) 表示请求使用版本 2.2 的 Winsock APIwsaData 是一个指向 WSADATA 结构体的指针Winsock 会将相关信息存储在这个结构体中。如果初始化失败WSAStartup 会返回非零值我们可以使用 WSAGetLastError() 获取错误代码。 为什么要加入 WSAStartup 和 WSACleanup Winsock 是 Windows 的网络编程接口它为 Windows 操作系统提供了网络应用程序接口API允许程序通过 TCP/IP 协议族进行通信。在 Windows 中使用 Socket 之前必须首先调用 WSAStartup 来初始化 Winsock 库。它的作用是让应用程序和 Winsock 层的网络操作系统组件建立联系。WSAStartup 会检查 Winsock 库的版本是否与系统兼容并加载网络功能所需的组件。每个成功调用 WSAStartup 的应用程序在程序结束时都需要调用 WSACleanup 来清理 Winsock 使用的资源。它会关闭网络资源并释放内存等以防止内存泄漏或其他资源问题。  这个步骤与在其他操作系统如 Linux中进行网络编程时的步骤不同因为 Linux 不需要这样的显式初始化操作。Linux 的网络 API 是直接通过系统调用实现的使用 socket 和相关函数时不需要先初始化网络库。  1.创建Socket 要创建一个Socket需要使用socket()函数。 SOCKET socket(int domain, int type, int protocol);domain通信协议族AF_INET用于IPv4AF_INET6用于IPv6。type指定Socket类型SOCK_STREAM用于TCPSOCK_DGRAM用于UDP。protocol一般设置为0即可由系统自动选择协议。 domain参数 该参数指明要创建的sockfd的协议族一般比较常用的有两个 AF_INETIPv4协议族AF_INET6IPv6协议族 type参数 该参数用于指明套接字类型具体有 SOCK_STREAM字节流套接字适用于TCP或SCTP协议SOCK_DGRAM数据报套接字适用于UDP协议SOCK_SEQPACKET有序分组套接字适用于SCTP协议SOCK_RAW原始套接字适用于绕过传输层直接与网络层协议IPv4/IPv6通信 protocol参数 该参数用于指定协议类型。 如果是TCP协议的话就填写IPPROTO_TCPUDP和SCTP协议类似。 也可以直接填写0这样的话则会默认使用domain参数和type参数组合制定的默认协议 参照上面type参数的适用协议 返回值 socket函数在成功时会返回套接字描述符失败则返回-1。失败的时候可以通过输出errno来详细查看具体错误类型。 例如下面的代码创建了一个TCP套接字如果失败会返回负值 SOCKET sockfd socket(AF_INET, SOCK_STREAM, 0); // 当 sockfd -1 则代表socket创建失败 if (sockfd 0) {perror(Socket creation failed);cout create listen socket failed !!! errcode: GetLastError() endl;return -1; }在底层C使用两个宏来表示 socket 创建状态 #define INVALID_SOCKET (SOCKET)(~0) #define SOCKET_ERROR (-1)2.绑定Socket 服务端的Socket需要绑定到指定的IP地址和端口以便客户端可以连接。绑定可以通过bind()函数来完成把一个本地协议地址赋予一个套接字。 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);sockfdSocket描述符即前一步创建的Socket。addr结构体sockaddr指针包含IP地址和端口信息。addrlenaddr结构体的大小。 例如下面这段代码将Socket绑定到本地IP地址和端口8080上 首先看一下sockaddr_in的底层我们一般根据这个结构体的底层的其中三个字段进行赋值然后与创建的套接字进行绑定 struct sockaddr_in {uint8_t sin_len; // 结构长度非必需short sin_family; // 地址族一般为AF_****格式常用的是AF_INETUSHORT sin_port; // 16位TCP或UDP端口号IN_ADDR sin_addr; // 32位IPv4地址CHAR sin_zero[8]; // 保留数据段一般置零 }; struct sockaddr_in server_address; server_address.sin_family AF_INET; server_address.sin_port htons(8080); // 指定端口大小端问题将本地转换成路由器使用的大端千百十个 server_address.sin_addr.s_addr INADDR_ANY; // 绑定到本地所有可用的IP // server_address.sin_addr.s_addr inet_addr(0.0.0.0); // 字符串IP地址转换成整数IP // 返回-1代表绑定错误 if (bind(sockfd, (struct sockaddr *)server_address, sizeof(server_address)) 0) {perror(Bind failed);cout create listen socket failed !!! errcode: GetLastError() endl;// 关闭连接closesocket(sockfd);return -1; }不同的计算机对数据的存储格式不一样比如 32 位的整数 0x12345678可以在内存里从高到低存储为 12-34-56-78 大端或者从低到高存储为 78-56-34-12小端。但是这对于网络中的数据来说就带来了一个严重的问题当机器从网络中收到 12-34-56-78 的数据时它怎么知道这个数据到底是什么意思 解决的方案也比较简单在传输数据之前和接受数据之后必须调用 htonl/htons 或 ntohl/ntohs 先把数据转换成网络字节序或者把网络字节序转换为机器的字节序。 我们注意到上面代码不管是赋值IP还是端口都不是直接赋值而是使用了类似htons()或htonl()的函数这便是字节排序函数。 不同的机子上对于多字节变量的字节存储顺序是不同的有大端字节序和小端字节序两种。如果我们将机子A的变量原封不动传到机子B上其值可能会发生变化导致数据传输异常。故我们需要引入一个通用的规范称为网络字节序。 #include WinSock2.huint16_t htons(uint16_t host16bitvalue); //host to network, 16bit uint32_t htonl(uint32_t host32bitvalue); //host to network, 32bit uint16_t ntohs(uint16_t net16bitvalue); //network to host, 16bit uint32_t ntohl(uint32_t net32bitvalue); //network to host, 32bit 3.服务端监听listen连接请求 我们在绑定成功后服务端Socket需要进入监听模式以便等待客户端的连接请求。监听通过listen()函数实现。 int listen(int sockfd, int backlog);sockfdSocket描述符。backlog等待连接的最大队列长度。 例如下面的代码将Socket设置为监听模式并允许最多3个客户端等待连接 if (listen(sockfd, 3) 0) {perror(Listen failed);cout create listen socket failed !!! errcode: GetLastError() endl;// 关闭连接closesocket(sockfd);return -1; }4.服务端接受accept客户端连接 当客户端尝试连接时服务端通过accept()函数接受连接。 SOCKET accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);sockfd服务端的监听Socket。addr指向存储客户端信息的sockaddr结构体。addrlenaddr结构体的大小。 例如下面代码accept()是一个阻塞函数会阻塞程序直到有客户端连接。如果连接成功会返回新的Socket用于与该客户端通信 struct sockaddr_in client_address; socklen_t client_address_len sizeof(client_address); while (1) {// 这里返回客户端的new_socket才是跟客户端可通讯的socketSOCKET new_socket accept(sockfd, (struct sockaddr*)client_address, client_address_len);if (new_socket INVALID_SOCKET) {perror(Accept failed);cout create listen socket failed !!! errcode: GetLastError() endl;// 直到创建可通讯的socket才能跳出循环continue;}// 开始通讯// 关闭连接 } 5.客户端连接connect服务端 客户端通过connect()函数向服务端发起连接。在调用connect函数的时候调用方也就是客户端便会主动发起TCP三次握手。 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);sockfd客户端的Socket。addr指向服务端地址的sockaddr结构体。addrlenaddr结构体的大小。 在操作上比较类似于服务端使用bind函数虽然做的事情完全不一样唯一的区别在于指定ip这块。服务端调用bind函数的时候无需指定ip但客户端调用connect函数的时候则需要指定服务端的ip。在客户端的代码中令套接字地址结构体指定ip的代码如下 inet_pton(AF_INET, SERVER_IP, servaddr.sin_addr); 这个就涉及到ip地址的表达格式与数值格式相互转换的函数。 IP地址格式转换函数 IP地址一共有两种格式 表达格式也就是我们能看得懂的格式例如192.168.19.12这样的字符串数值格式可以存入套接字地址结构体的格式数据类型为整型 显然当我们需要将一个IP赋进套接字地址结构体中就需要将其转换为数值格式。#include WinSock2.h提供了两个函数用于IP地址格式的相互转换 // 将IP地址从表达格式转换为数值格式 int inet_pton(int domain, const char *strptr, void *addrptr); // 将IP地址从数值格式转换为表达格式 const char *inet_ntop(int domain, const void *addrptr, char *strptr, size_t len); 下面代码的作用是将客户端连接到本地地址127.0.0.1的端口8080上 struct sockaddr_in server_address; server_address.sin_family AF_INET; server_address.sin_port htons(8080); inet_pton(AF_INET, 127.0.0.1, server_address.sin_addr);if (connect(sockfd, (struct sockaddr *)server_address, sizeof(server_address)) -1) {printf(Connect error(%d): %s\n, errno, strerror(errno));closesocket(sockfd);return -1; }6.数据传输 一旦建立连接客户端和服务端就可以使用send()和recv()来交换数据。 send()用于发送数据。recv()用于接收数据。 while (1) {struct sockaddr_in client_address;int client_address_len sizeof(client_address);// 这里返回客户端的new_socket才是跟客户端可通讯的socketSOCKET new_socket accept(sockfd, (struct sockaddr*)client_address, client_address_len);if (new_socket INVALID_SOCKET) {perror(Accept failed);cout create listen socket failed !!! errcode: GetLastError() endl;// 直到创建可通讯的socket才能跳出循环continue;}// 开始通信B/Schar buffer[1024] { 0 };recv(new_socket,buffer,1024,0);// 关闭连接closesocket(new_socket); } 客户端发送请求服务器接收请求并返回响应。由于 TCP 是面向流的协议recv 和 send 需要处理流式数据。数据可能会被分割成多个包发送也可能会接收到部分数据因此需要处理数据的拼接和分包。recv 和 send 在默认情况下是阻塞的调用者会等待数据的发送或接收完成。通过设置 MSG_DONTWAIT 等标志可以实现非阻塞模式。 1recv的使用 下面是recv()的底层代码 recv(SOCKET s, // 客户端socketchar* buf, // 接受的数据存到哪里int len, // 接受的长度int flags // 标记0); 如果发送成功返回实际发送的字节数。如果发送的数据量大于缓冲区大小返回的值可能小于 len此时需要调用 send 发送剩余的数据。如果发生错误返回 -1并且设置 errno可以使用 perror() 或 strerror() 获取错误信息。 2send的使用 send(SOCKET s,const char* buf,int len,int flags); sockfd表示一个已经建立连接的Socket描述符。你可以通过调用 socket() 创建一个Socket并通过 connect()客户端或 accept()服务器建立连接。buf一个指向数据的指针表示要发送的数据缓冲区。通常是一个字符数组或字符串。len要发送的字节数。这个长度指的是缓冲区中的数据的大小。flags发送时的标志。常见的标志有 0表示默认行为。MSG_DONTWAIT在非阻塞模式下使用表示如果没有数据可以发送send()函数将立刻返回而不是阻塞。MSG_NOSIGNAL如果套接字已关闭不会抛出信号只适用于某些平台如Linux。 7.关闭closesocketSocket 通信完成后需要关闭Socket释放资源。可以使用closesocket()函数来关闭Socket。 closesocket(sockfd); 8.案例分析 编写服务端代码能够使打开浏览器访问http://127.0.0.1:8080/可以显示“Hello, World!”。 TCP 服务器需要以下步骤 创建 Socket。绑定 Socket 到一个特定的地址和端口。监听端口等待客户端连接。接受客户端连接并处理数据。关闭连接。 #include iostream #include string.h #include WinSock2.h #pragma comment(lib,ws2_32.lib) using namespace std;int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), wsaData) ! 0) {cerr WSAStartup failed: WSAGetLastError() endl;return -1;}// 创建Socket套接字SOCKET sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd INVALID_SOCKET) {cerr Socket creation failed: WSAGetLastError() endl;WSACleanup();return -1;}// 绑定Socket到IP和端口struct sockaddr_in server_address { 0 };server_address.sin_family AF_INET;server_address.sin_addr.s_addr inet_addr(0.0.0.0);server_address.sin_port htons(8080);if (bind(sockfd, (struct sockaddr*)server_address, sizeof(server_address)) SOCKET_ERROR) {cerr Bind failed: WSAGetLastError() endl;closesocket(sockfd);WSACleanup();return -1;}// 开始监听if (listen(sockfd, 3) 0) {cerr Listen failed: WSAGetLastError() endl;closesocket(sockfd);WSACleanup();return -1;}cout Waiting for connections on port 8080...\n;while (true) {struct sockaddr_in client_address;int client_address_len sizeof(client_address);// 接受客户端连接SOCKET new_socket accept(sockfd, (struct sockaddr*)client_address, client_address_len);if (new_socket INVALID_SOCKET) {cerr Accept failed: WSAGetLastError() endl;continue;}// 接收客户端请求char buffer[1024] { 0 };recv(new_socket, buffer, sizeof(buffer), 0);cout Received request:\n buffer endl;// 构造并发送简单的HTTP响应,包括状态行、响应头和响应体内容为“Hello, World!”const char* http_response HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 13\r\n\r\nHello, World!;send(new_socket, http_response, strlen(http_response), 0);// 关闭连接closesocket(new_socket);}// 清理Socketclosesocket(sockfd);WSACleanup();return 0; }编写客户端代码 TCP 客户端需要以下步骤 创建 Socket。连接到服务器的 IP 地址和端口。发送数据给服务器。接收来自服务器的响应。关闭连接。 #include iostream #include WinSock2.h #pragma comment(lib, ws2_32.lib)using namespace std;int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), wsaData) ! 0) {cerr WSAStartup failed: WSAGetLastError() endl;return -1;}// 创建 SocketSOCKET clientSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (clientSocket INVALID_SOCKET) {cerr Socket creation failed: WSAGetLastError() endl;WSACleanup();return -1;}// 设置服务器地址sockaddr_in serverAddr;serverAddr.sin_family AF_INET;serverAddr.sin_port htons(8080); // 连接到服务器的 8080 端口serverAddr.sin_addr.s_addr inet_addr(127.0.0.1); // 服务器地址本地地址// 连接到服务器if (connect(clientSocket, (sockaddr*)serverAddr, sizeof(serverAddr)) SOCKET_ERROR) {cerr Connection failed: WSAGetLastError() endl;closesocket(clientSocket);WSACleanup();return -1;}cout Connected to server. endl;// 发送数据const char* message Hello, Server!;if (send(clientSocket, message, strlen(message), 0) SOCKET_ERROR) {cerr Send failed: WSAGetLastError() endl;closesocket(clientSocket);WSACleanup();return -1;}// 接收响应char buffer[1024] {0};int bytesReceived recv(clientSocket, buffer, sizeof(buffer), 0);if (bytesReceived 0) {cout Server says: buffer endl;} else if (bytesReceived 0) {cout Connection closed by server. endl;} else {cerr Receive failed: WSAGetLastError() endl;}// 关闭连接closesocket(clientSocket);WSACleanup();return 0; }三.TCP协议流程 TCP 协议是面向连接的它在客户端和服务器之间建立一个可靠的连接。具体流程如下 TCP三次握手建立连接 客户端向服务器发送一个 SYN 请求包表示要建立连接。服务器收到后回复一个 SYN-ACK 包表示同意连接。客户端收到后发送一个 ACK 包确认连接建立。 A客户端: CLOSED - SYN_SENT - ESTABLISHED B服务端: LISTEN监听状态 - SYN_RCVD - ESTABLISHED 首先客户端主动调用connect发送一个SYN包如TCP首部和TCP选项等协议包必须数据来对服务端请求连接此时客户端的状态从CLOSED转换成SYN_SENT。 在socket编程中服务端调用过listen函数使其处于监听状态并且处于accept函数等待连接的阻塞状态下才能收到SYN包返回一个针对该SYN包的响应包ACK包和一个新的SYN包此时服务端状态由LISTEN转换成SYN_RCVD。 随后客户端收到服务端发来的两个包并返回针对新的SYN包的ACK包。此时客户端的状态从SYN_SENT切换至ESTABLISHED处于这个状态的客户端就可以传输数据了。 服务端收到ACK包后代表成功建立连接这时调用accept函数返回客户端套接字同样服务端的状态由SYN_RCVD切换至ESTABLISHED同样处于这个状态的服务端就可以传输数据了。 数据传输 一旦连接建立客户端和服务器就可以通过 send() 和 recv() 来发送和接收数据 TCP四次挥手断开连接 客户端或服务器中的任一方可以发送 FIN 包表示断开连接。对方收到后会回复一个 ACK 包确认断开。最后发送 FIN 包的方再收到对方的 ACK 包连接彻底关闭。 假设A主动关闭连接A与B的流程转换图如下  A: ESTABLISHED - FIN_WAIT_1 - FIN_WAIT_2 - TIME_WAIT - CLOSED B:ESTABLISHED - CLOSE_WAIT - LAST_ACK - CLOSED 在收发数据之后如果需要断开连接方中有一方假设为A另一方为B主动关闭连接调用close函数或者其进程本身被终止等情况则其向B发送FIN包。此时A的状态从ESTABLISHED转换成FIN_WAIT_1。 B接收到A传递的FIN包后发送ACK包此时B的状态从ESTABLISHED转换成CLOSE_WAIT。 随后A接收到B传递的ACK包后此时A的状态从FIN_WAIT_1转换成FIN_WAIT_2。 过一段时间后B调用close函数发送FIN包此时B的状态从CLOSE_WAIT转换成LAST_ACK。 A接收到FIN包并发送ACK包此时A的状态由FIN_WAIT_2转换成TIME_WAIT。 B接收到ACK包后关闭连接此时B的状态从LAST_ACK转换成CLOSED。 A等待一段时间后关闭连接此时A的状态从TIME_WAIT转换成CLOSED状态。 四.UDP协议流程 UDP用户数据报协议是一种无连接的网络协议与 TCP 相比UDP 不会建立连接并且不保证数据的可靠性适用于需要高速传输且容忍丢包的场景。UDP 编程相对简单因为不需要像 TCP 一样进行连接和握手但也因为没有连接管理数据可能会丢失。 前置知识 UDP 的特性  UDP 不需要在发送数据前建立连接这使得它比 TCP 更加高效尤其是在大量数据传输时。但UDP 不保证数据的可靠送达因此不会进行重传、流量控制和拥塞控制。如果需要可靠性应用层需要自己处理。UDP 发送的数据包可能会乱序接收应用层需要处理顺序问题。  UDP的使用 UDP 是无连接的它不需要像 TCP 那样进行握手适合需要高效传输且容忍数据丢失的应用场景。UDP 不需要像 TCP 那样进行三次握手建立连接也没有四次挥手断开连接。每次通信都是独立的发送方和接收方都可以在任意时间发送和接收数据包。在 C 中使用 UDP 编程时创建 Socket 使用 SOCK_DGRAM 类型数据的发送和接收使用 sendto() 和 recvfrom()不需要使用 connect()。UDP没有可靠性保证应用程序需要自行确保数据的完整性和顺序或者使用更高层的协议来处理。  接收和发送数据的函数 在 Socket 编程中recvfrom() 和 sendto() 是 UDP 协议下用于接收和发送数据的函数。这些函数是 UDP 套接字通信的关键它们支持无连接的数据传输允许在网络上发送和接收数据报Datagram。这两者是 UDP 套接字编程中最常用的函数因为它们简化了数据传输的过程并支持多播和广播通信。 recvfrom() 函数 recvfrom() 是用于接收来自指定源IP 地址和端口的数据报的函数。在 UDP 通信中数据报是独立的、无连接的这意味着每个数据包可以有不同的来源和目标。 int recvfrom(SOCKET s, // 套接字描述符char *buf, // 缓冲区用于存储接收到的数据int len, // 缓冲区的大小int flags, // 接收标志通常为 0struct sockaddr *from, // 来源地址接收到数据报的来源地址int *fromlen // 来源地址的长度 );示例UDP 服务器端使用 recvfrom() recvfrom() 接收数据并存储在 buffer 中。clientAddr 保存了发送者的 IP 地址和端口号。bytesReceived 记录了成功接收的字节数。  char buffer[1024]; sockaddr_in clientAddr; int clientAddrSize sizeof(clientAddr);// 接收数据 int bytesReceived recvfrom(serverSocket, buffer, sizeof(buffer), 0, (sockaddr*)clientAddr, clientAddrSize); if (bytesReceived SOCKET_ERROR) {cerr Receive failed: WSAGetLastError() endl; } else {cout Received: buffer endl; }sendto() 函数 sendto() 用于向指定的目标地址发送数据报。由于 UDP 是无连接的协议数据包发送时需要显式地指定目标地址和端口。 int sendto(SOCKET s, // 套接字描述符const char *buf, // 需要发送的数据int len, // 数据的长度int flags, // 发送标志通常设为 0const struct sockaddr *to, // 目标地址发送数据报的目标地址int tolen // 目标地址的长度 );示例UDP 客户端使用 sendto() sendto() 将消息发送到 127.0.0.1 上的端口 8080。目标地址是 serverAddr它包含了目标服务器的 IP 地址和端口号。 const char* message Hello, Server!; sockaddr_in serverAddr; serverAddr.sin_family AF_INET; serverAddr.sin_port htons(8080); serverAddr.sin_addr.s_addr inet_addr(127.0.0.1);// 发送数据 int bytesSent sendto(clientSocket, message, strlen(message), 0, (sockaddr*)serverAddr, sizeof(serverAddr)); if (bytesSent SOCKET_ERROR) {cerr Send failed: WSAGetLastError() endl; } else {cout Message sent to server. endl; }1.UDP的服务端 UDP 服务器端的主要工作是 创建一个 Socket。绑定bind Socket 到一个指定的端口。接收来自客户端的数据没有连接过程。发送数据回客户端如果需要。 初始化 Winsock调用 WSAStartup() 初始化 Winsock 库。创建 UDP Socket使用 socket() 创建一个 UDP SocketSOCK_DGRAM 表示数据报类型的套接字。设置服务器地址设置服务器的 IP 地址和端口使用 INADDR_ANY 来绑定所有网络接口。绑定 Socket通过 bind() 将 Socket 绑定到指定的地址和端口。接收数据通过 recvfrom() 接收来自客户端的数据不需要建立连接因为 UDP 是无连接的。接收的数据会被存放在 buffer 中clientAddr 用来保存客户端的地址信息。发送响应使用 sendto() 向客户端发送数据。由于是无连接的每次发送时都需要指定客户端的地址信息。关闭 Socket程序结束后通过 closesocket() 关闭 Socket。 #include iostream #include WinSock2.h #pragma comment(lib, ws2_32.lib)using namespace std;int main() {// 调用 WSAStartup() 初始化 Winsock 库。WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), wsaData) ! 0) {cerr WSAStartup failed: WSAGetLastError() endl;return -1;}// 使用 socket() 创建一个 UDP SocketSOCK_DGRAM 表示数据报类型的套接字。SOCKET serverSocket socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (serverSocket INVALID_SOCKET) {cerr Socket creation failed: WSAGetLastError() endl;WSACleanup();return -1;}// 设置服务器的 IP 地址和端口使用 INADDR_ANY 来绑定所有网络接口。sockaddr_in serverAddr;serverAddr.sin_family AF_INET;serverAddr.sin_port htons(8080); // 设置端口serverAddr.sin_addr.s_addr htonl(INADDR_ANY); // 绑定所有网络接口// 绑定 Socket,通过 bind() 将 Socket 绑定到指定的地址和端口if (bind(serverSocket, (sockaddr*)serverAddr, sizeof(serverAddr)) SOCKET_ERROR) {cerr Bind failed: WSAGetLastError() endl;closesocket(serverSocket);WSACleanup();return -1;}cout Server listening on port 8080... endl;// 接收数据char buffer[1024] {0};sockaddr_in clientAddr;int clientAddrSize sizeof(clientAddr);while (true) {// 通过 recvfrom() 接收来自客户端的数据不需要建立连接因为 UDP 是无连接的。// 接收的数据会被存放在 buffer 中clientAddr 用来保存客户端的地址信息。int bytesReceived recvfrom(serverSocket, buffer, sizeof(buffer), 0, (sockaddr*)clientAddr, clientAddrSize);if (bytesReceived SOCKET_ERROR) {cerr Receive failed: WSAGetLastError() endl;continue;}cout Received: buffer endl;// 向客户端发送响应const char* response Message received!;// 使用 sendto() 向客户端发送数据。由于是无连接的每次发送时都需要指定客户端的地址信息。int bytesSent sendto(serverSocket, response, strlen(response), 0, (sockaddr*)clientAddr, sizeof(clientAddr));if (bytesSent SOCKET_ERROR) {cerr Send failed: WSAGetLastError() endl;}}// 程序结束后通过 closesocket() 关闭 Socket。closesocket(serverSocket);// 释放Winsock资源WSACleanup();return 0; }2.UDP的客户端 UDP 客户端的主要工作是 创建一个 Socket。向服务器发送数据。接收来自服务器的响应。 初始化 Winsock同样需要初始化 Winsock。创建 UDP Socket创建一个 UDP 类型的 Socket。设置服务器地址设置服务器的 IP 地址和端口。发送数据使用 sendto() 向服务器发送数据。UDP 不需要建立连接因此发送时直接指定服务器的地址。接收数据通过 recvfrom() 接收来自服务器的响应。关闭 Socket最后关闭客户端的 Socket。 #include iostream #include WinSock2.h #pragma comment(lib, ws2_32.lib)using namespace std;int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), wsaData) ! 0) {cerr WSAStartup failed: WSAGetLastError() endl;return -1;}// 创建 UDP SocketSOCKET clientSocket socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (clientSocket INVALID_SOCKET) {cerr Socket creation failed: WSAGetLastError() endl;WSACleanup();return -1;}// 设置服务器地址sockaddr_in serverAddr;serverAddr.sin_family AF_INET;serverAddr.sin_port htons(8080); // 服务器端口号serverAddr.sin_addr.s_addr inet_addr(127.0.0.1); // 服务器地址// 发送数据const char* message Hello, Server!;int bytesSent sendto(clientSocket, message, strlen(message), 0, (sockaddr*)serverAddr, sizeof(serverAddr));if (bytesSent SOCKET_ERROR) {cerr Send failed: WSAGetLastError() endl;closesocket(clientSocket);WSACleanup();return -1;}// 接收响应char buffer[1024] {0};sockaddr_in serverResponseAddr;int serverResponseAddrSize sizeof(serverResponseAddr);int bytesReceived recvfrom(clientSocket, buffer, sizeof(buffer), 0, (sockaddr*)serverResponseAddr, serverResponseAddrSize);if (bytesReceived SOCKET_ERROR) {cerr Receive failed: WSAGetLastError() endl;} else {cout Server says: buffer endl;}// 关闭 Socketclosesocket(clientSocket);WSACleanup();return 0; }五.前置基础知识总结 详细知识可参考下面文档C/C网络编程基础知识超详细讲解第一部分系统性学习day11-阿里云开发者社区  1. 网络基础知识 IP 地址计算机在网络中的唯一标识。端口号应用程序通过端口号与网络中的其他计算机进行通信。协议通信协议用于规范计算机间如何传输数据最常用的协议有 TCP 和 UDP。路由和网络层次结构数据如何在不同的网络设备之间转发网络中的路由和地址解析协议如 ARP是如何工作的。网络模型OSI 七层模型和 TCP/IP 四层模型。 OSI 模型物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。TCP/IP 模型网络接口层、互联网层、传输层、应用层。 2. Socket 的基本概念 Socket 是网络通信的接口是操作系统提供的用于建立网络通信的抽象层。需要了解以下概念 套接字Socket是应用程序与网络进行通信的端点。Socket 类型常见的有 流式套接字SOCK_STREAM基于 TCP 协议保证数据传输可靠适用于需要高可靠性的应用。数据报套接字SOCK_DGRAM基于 UDP 协议不保证数据的可靠传输适用于快速、简单的通信。协议族Protocol Family通常使用 AF_INETIPv4或 AF_INET6IPv6等。连接类型 面向连接的Connection-oriented如 TCP传输之前需要建立连接。无连接的Connectionless如 UDP数据包在发送时不需要先建立连接。 3. Socket 编程中的常用 API 在学习 Socket 编程时我们会用到很多函数来创建、绑定、监听、发送、接收、关闭套接字等。以下是常用的 Socket 编程函数 创建和管理 Socket socket()创建一个套接字。bind()将套接字与本地地址IP 地址和端口绑定。listen()在服务器端用于监听端口准备接受连接。accept()在服务器端接受客户端的连接请求。connect()在客户端连接到服务器端。close()关闭套接字。 发送和接收数据 send()在已连接的 TCP 套接字上发送数据。recv()从已连接的 TCP 套接字接收数据。sendto()在 UDP 套接字上发送数据需要指定目标地址。recvfrom()从 UDP 套接字接收数据返回数据源的地址信息。 地址结构和网络信息 sockaddr_in用于指定 IPv4 地址和端口。gethostbyname()根据域名获取 IP 地址。inet_pton() 和 inet_ntop()用于在点分十进制Dotted Decimal和二进制表示之间转换 IP 地址。 4. 常见的 Socket 编程模式 客户端-服务器模式 服务器端等待客户端的连接客户端向服务器发起连接请求建立起通信后交换数据。 广播和多播 UDP 支持广播和多播通信 广播发送数据包到网络中的所有主机指定广播地址。多播发送数据包到特定的组播地址只有加入该组的主机才能接收到数据。 5. 网络调试和错误处理  在编写 Socket 程序时调试和处理错误是非常重要的 错误处理每个 Socket 函数调用后都应该检查其返回值如果返回错误需要根据 errno 或 WSAGetLastError() 获取错误信息。网络工具如 ping、traceroute、netstat 等工具帮助检查网络连接状况。
http://www.dnsts.com.cn/news/229990.html

相关文章:

  • 省级网站 开发建设 资质珠海做网站哪间好
  • 旅游网站的规划与建设开题报告wordpress怎么修改中文字体
  • jsp网站建设模板下载lnmp下安装wordpress
  • 网站建设公司厦门有哪些温州瑞安网站建设平台
  • 哪些网站可以做驾考试题婚庆策划公司简介
  • 广州市网站建设管理员工的10个绝招
  • 深圳做装修网站费用多少学校做网站的软件
  • 如何做网站推广页面做坑人网站二维码
  • 才艺多网站建设公司app外包平台大概多少钱
  • 建设电子商务网站背景wordpress 使用ip访问不了
  • 吉安建站公司网站的素材做logo
  • 网站建设模板研究租房合同模板免费下载
  • 网站上线要准备什么在线设计logo图片
  • 电商专业网站建设的毕业设计wordpress搜索栏
  • 网站建设属于什么职能建筑工程公司电话都怎么查找
  • 东莞网站推广行者seo08网站开发产品经理
  • 家用网络建网站青岛企业展厅设计公司
  • 宁乡网站建设中卫网站设计公司招聘
  • 树形菜单的网站代码创办网站需要什么
  • 做电影平台网站怎么赚钱吗素材分享网站源码
  • 自适应网站模版金山开发
  • 办公用品网站建设太原做手机网站设计
  • 维护网站网络运营商在哪里找
  • 太原在线网站建设手机排行榜2022年
  • 什么公司做网站的多去越南做网站
  • 网站开发能赚钱吗飞机网页设计实训报告
  • 重庆网站网页设计培训机构软件网站是怎么做的吗
  • 自己怎么做网站首页盐城城南建设局一局网站
  • 网页设计模板网站免费下载长春网站建设电话
  • 如何制作公司网站和网页app制作平台大全