TCP/UDP 套接字的编写

文章目录

      • 基础知识
    • socket编程
      • UDP套接字编程
      • TCP套接字编写
    • 套接字编写注意事项

基础知识

  • IP地址互联网协议地址(Internet Protocol Address),分配给互联网互联中设备的单一标识,理解成生活中的邮箱地址是比较类似的。在不同的地方入网,就会有不同的ip地址
  • 端口号(port):没操作系统的知识的话,说的粗陋一点,就是如何识别在体态设备上与不同的APP通信,给这些APP分配一个ID,这个ID就叫做端口号。当然前面说法并不完全正确,准确的是端口号应该是区别一台主机中该网络信息向上交付时,是应该交由哪个进程处理而端口号就是用来做这个的。和进程PID有点类似但又有所不同。
    • 一个进程可以有多个port,因为其可以同时收到多个不同的网络消息。
    • 一个port只能对应一个进程,因为他就是用来标识信息向上交付时交给哪个进程的
    • 端口号的范围从0到65535,其中一些知名的端口(0-1023)被预留给标准服务,比如HTTP使用80端口,HTTPS使用443端口,FTP使用21端口等。而动态或私有端口(通常指从1024到65535)则通常是临时分配给应用程序的,尤其是在客户端或不固定服务场景中
  • 网络字节序:就是大小端存储的问题,网络中发送的数据需要考虑大小端,网络规定的标准是大端
    • Big-endian:大端,指一个数据的低字节部分存在高地址处
    • Little-endian:小端,。指一个数据他的低字节处 存储在低地址处。
    • 例子:一个2字节数据:0x11 22 ,加入从左向右地址是增长的,那么大端里面:0x11 22 ;小端:0x22 11
    • 这里说一下我自己容易搞错的点,数据的右边一般才是低字节序,数据的左边一般是高字节序列。你想一个整数,百位肯定是高位把。
    • linux/windows系统都有提供的从主机转网络,网络转主机的函数
    • htonl
    • htons
    • ntohl
    • ntohs

socket编程

socket编程虽然里面需要填写的字段十分多,但是大多数场景下基本类似。
先来整体认识下一些必须要掌握的基础知识
常用接口(windows和linux的函数名都是一样的,但是由于系统不同,其中有些参数类型可能不太一样,以下以WIndows为例,linux你可以使用man + 函数名查看具体情况)
这些常用接口除了类型有一些略微不同,其中许多宏常量,linux和Windows下几乎都是一样的。下面介绍的函数名windows和linux基本都共有。

  • socket
  SOCKET WSAAPI socket([in] int af,   // 常常传入 AF_INET 或者AF_INET6[in] int type,  [in] int protocol);
    • [in]是windows文档的一种习惯,表示这个参数是一个输入形参数
    • af是协议家族, 常常传入 AF_INET 或者AF_INET6。你是ipv4地址就传入AF_INET,ipv6就选AF_INET6
    • type 重点了解,UDP传入SOCK_DGRAM,TCP传入SOCK_STREAM。其余选项可自行取查看手册
    • protocol:如果af,type指定了ipv4/6的协议家族和对应的类型,那么这里传入0由系统给你自动匹配协议是最好。的。如果你传入的是类似SOCK_RAW的值,那这里就需要你特殊指定,这个选项是用来精确控制套接字收到的数据。
  • 返回值
    如果未发生错误, 套接字 将返回引用新套接字的描述符。 否则,将返回值 INVALID_SOCKET,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。

  • bind :一般服务端使用

* int bind([in] SOCKET         s,const sockaddr *addr,[in] int     namelen
);
  • 参数

    • [in] s
      标识未绑定套接字的描述符。
    • addr
      指向要分配给绑定套接字 的本地地址 的 sockaddr 结构的指针。
    • [in] namelen
      addr 指向的值的长度(以字节为单位)。
  • 返回值

  • 如果未发生错误, 绑定 将返回零。 否则,它将返回SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。

谈到bind,就必须提及Socket编程里面需要的用的结构体sockaddr ,sockaddr_in,sockaddr_in6

  • 使用bind时,一般先创建都应的sockaddr_in(ipv4),sockaddr_in6(ipv6)的。填写其中的家族,端口号,和ip地址。
  • 在强转成 sockaddr* 传入对应的函数bind处理即可。
  • 其中要注意主机大小端和ip地址格式问题。用上述的网络字节序处的函数转变端口号
  • ip地址和和主机之间相互转换的时候,库里面的函数
    如下:

int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);
in_addr_t inet_addr(const char *cp);
inet_ntop, inet_pton:这两个是都支持的
下面几个用的相对较少,可以使用时查文档
ntohf
ntohl
ntohll
ntohs

struct sockaddr {ushort  sa_family;char    sa_data[14];
};struct sockaddr_in {short   sin_family;u_short sin_port;struct  in_addr sin_addr;char    sin_zero[8];
};struct sockaddr_in6 {short   sin6_family;u_short sin6_port;u_long  sin6_flowinfo;struct  in6_addr sin6_addr;u_long  sin6_scope_id;
};

上面两个操作TCP和UDP都会用到,但是下面介绍的就是TCP才用了

  • listen :一般是TCP服务端代码使用
int WSAAPI listen([in] SOCKET s,[in] int    backlog
);
  • 参数解释

    • [in] s 标识绑定的未连接的套接字的描述符。
    • [in] backlog 挂起的连接队列的最大长度。
  • 返回值:如果未发生错误, 则侦听 返回零。 否则,将返回 值 SOCKET_ERROR ,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。

  • accept :一般时TCP服务器端使用

SOCKET WSAAPI accept([in]      SOCKET   s,[out]     sockaddr *addr,[in, out] int      *addrlen
);
  • 参数
    [in] s :一个描述符,用于标识已使用 侦 听函数置于侦听状态的套接字。 连接实际上是使用 accept 返回的套接字建立的。
    [out] :addr指向接收连接实体地址的缓冲区的可选指针,该地址称为通信层。 addr 参数的确切格式由创建 sockaddr 结构中的套接字时建立的地址系列确定。
    [in, out] :addrlen指向包含 addr 参数指向的结构长度的整数的可选指针。

  • 返回值
    果未发生错误, 则 accept 将返回 类型为 SOCKET 的值,该值是新套接字的描述符。 此返回值是建立实际连接的套接字的句柄。
    否则,将返回 值 INVALID_SOCKET ,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。

这里返回值拿到的套接字正常读取写入就能和客户端通信了,当成文件描述符使用即可,当然用send和recv来收发数据也可以。

  • connect :一般TCP客户端代码使用
    • 参数
      [in] s 标识未连接的套接字的描述符。
      [in] name 指向应建立连接的 sockaddr 结构的指针。
      [in] namelen name 参数指向的 sockaddr 结构的长度(以字节为单位)。

    • 返回值
      如果未发生错误, 则连接 返回零。 否则,它将返回SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。

链接成功后就可以使用,当成文件描述符来使用也是没有问题的。当然用send和recv来收发数据也可以

UDP套接字编程

UDP套接字就只需要两个操作,socket和bind,做完之后UDP程序就能通信了。
具体步骤
服务器

  • 先申请一个套接字,填入对应的sockaddr的字段
  • 再bind 改套接字即可
  • 再用sendto 和 recv收发数据

客户端:

  • 创建一个套接字
  • 用sendto 和recv发收数据即可
    Server
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>#pragma comment(lib, "ws2_32.lib")int main() {//使用windows网络库需要做的,linux下就没这过程WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cerr << "Failed to initialize winsock." << std::endl;return -1;}SOCKET serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (serverSocket == INVALID_SOCKET) {std::cerr << "Failed to create socket." << std::endl;WSACleanup();return -1;}sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(12345); // 服务器监听端口serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {std::cerr << "Failed to bind socket." << std::endl;closesocket(serverSocket);WSACleanup();return -1;}std::cout << "Server is listening on port 12345..." << std::endl;char buffer[1024];sockaddr_in clientAddr;int addrLen = sizeof(clientAddr);while (true) {int bytesReceived = recvfrom(serverSocket, buffer, sizeof(buffer), 0, (SOCKADDR*)&clientAddr, &addrLen);if (bytesReceived > 0) {buffer[bytesReceived] = '\0';std::cout << "Message from client: " << buffer << std::endl;// Echo back the message to the clientsendto(serverSocket, buffer, bytesReceived, 0, (SOCKADDR*)&clientAddr, sizeof(clientAddr));}}closesocket(serverSocket);WSACleanup();return 0;
}

Client


#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>#pragma comment(lib, "ws2_32.lib")int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cerr << "Failed to initialize winsock." << std::endl;return -1;}SOCKET clientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (clientSocket == INVALID_SOCKET) {std::cerr << "Failed to create socket." << std::endl;WSACleanup();return -1;}sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(12345); // 服务器端口号inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr); // 服务器IP地址,这里假设为本地环回地址std::string message;std::cout << "Enter a message to send to the server: ";std::getline(std::cin, message);if (sendto(clientSocket, message.c_str(), message.length(), 0, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {std::cerr << "Failed to send message." << std::endl;} else {std::cout << "Message sent to server." << std::endl;}char buffer[1024];int bytesReceived = recvfrom(clientSocket, buffer, sizeof(buffer), 0, NULL, NULL);if (bytesReceived > 0) {buffer[bytesReceived] = '\0';std::cout << "Reply from server: " << buffer << std::endl;}closesocket(clientSocket);WSACleanup();return 0;
}

TCP套接字编写

服务端:

  • socket获取一个套接字
  • bind这个套接字
  • 监听这个套接字
  • accept,接受链接成功返回一个套接字,用该套接字通信即可。用send和recv进行通信即可。可以接受多个套接字

客户端:

  • socket 获取一个套接字
  • connect 对应的服务器,成功后用该套接字 send和recv即可。

linux下一切皆文件,TCP这里读取内容的时候,其实用read和write来收发数据也是没有问题的。

服务器代码

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>#pragma comment(lib, "ws2_32.lib")int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {printf("WSAStartup failed: %d\n", GetLastError());return 1;}SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (ListenSocket == INVALID_SOCKET) {printf("Error at socket(): %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"); // 或者使用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: %ld\n", WSAGetLastError());closesocket(ListenSocket);WSACleanup();return 1;}printf("Listening on port 27015...\n");SOCKET ClientSocket;while ((ClientSocket = accept(ListenSocket, NULL, NULL)) != INVALID_SOCKET) {char recvbuf[512];int iResult = recv(ClientSocket, recvbuf, 512, 0);if (iResult > 0)printf("Received: %s\n", recvbuf);else if (iResult == 0)printf("Connection closing...\n");elseprintf("recv failed: %d\n", WSAGetLastError());// 发送响应(可选)char *response = "Hello from server!";send(ClientSocket, response, strlen(response), 0);closesocket(ClientSocket);}if (ClientSocket == INVALID_SOCKET) {printf("accept failed: %d\n", WSAGetLastError());closesocket(ListenSocket);WSACleanup();return 1;}closesocket(ListenSocket);WSACleanup();return 0;
}
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>#pragma comment(lib, "ws2_32.lib")int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {printf("WSAStartup failed: %d\n", GetLastError());return 1;}SOCKET ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (ConnectSocket == INVALID_SOCKET) {printf("Error at socket(): %ld\n", WSAGetLastError());WSACleanup();return 1;}sockaddr_in serverAddress;serverAddress.sin_family = AF_INET;serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器IP地址serverAddress.sin_port = htons(27015); // 与服务器端相同的端口号if (connect(ConnectSocket, (SOCKADDR*)&serverAddress, sizeof(serverAddress)) == SOCKET_ERROR) {printf("connect failed: %d\n", WSAGetLastError());closesocket(ConnectSocket);WSACleanup();return 1;}char sendbuf[] = "Hello from client!";int iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);if (iResult == SOCKET_ERROR) {printf("send failed: %d\n", WSAGetLastError());closesocket(ConnectSocket);WSACleanup();return 1;}char recvbuf[512];iResult = recv(ConnectSocket, recvbuf, 512, 0);if (iResult > 0)printf("Received: %s\n", recvbuf);else if (iResult == 0)printf("Connection closed\n");elseprintf("recv failed: %d\n", WSAGetLastError());closesocket(ConnectSocket);WSACleanup();return 0;
}

套接字编写注意事项

  • TCP和UDP都是全双工的,不用担心收发数据互相干扰的问题
  • 为了收发不互相干扰,一般要采取并发

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/17189.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac pro 解决No module named ‘_lzma‘

问题描述: Traceback (most recent call last): File "/Users/liutiecheng/Tylers Job/finetuning/tiny/train.py", line 1, in <module> import datasets …… import lzma File "/Users/liutiecheng/.pyenv/versions/3.9.2/lib/python3.9/lzma.py&quo…

HubSpot企业商机管理和销售自动化:提升业务效率的利器

在当今数字化时代&#xff0c;企业出海已成为拓展市场、增加营收的重要途径。然而&#xff0c;如何高效地管理商机和实现销售自动化&#xff0c;成为许多企业面临的挑战。HubSpot作为一款强大的营销、销售和服务自动化平台&#xff0c;为企业提供了全方位的解决方案。今天运营坛…

图解 BERT 模型

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学. 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总合集&…

busco,checkM2,checkM:基因组或MAG完整度分析

busco安装&#xff08;应该是一般用于真核生物&#xff09; mamba create -n BUSCO biopython1.79 conda activate BUSCO mamba install -c bioconda python3.8 sepp4.3.10 mamba install -c bioconda busco5.7.1 busco 使用 #下载数据库&#xff08;2024-01-08&#xff09…

【Docker】docker-compose 常用命令

启动服务&#xff1a; docker-compose up 如果你想在后台运行服务&#xff0c;可以添加 -d 标志&#xff1a; docker-compose up -d 开启所有服务 docker-compose start 停止服务&#xff1a; docker-compose down 查看服务状态&#xff1a; docker-compose ps 查看…

5-21作业

流式域套接字 服务器端实现 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> #include <semaphore.h> #include <…

Host头攻击

Host头攻击&#xff08;也被称为HTTP Host头注入攻击&#xff09;是一种Web安全漏洞&#xff0c;攻击者通过篡改HTTP请求中的Host头部字段来执行恶意操作。在HTTP协议中&#xff0c;Host头部字段用于指定请求所针对的域名&#xff0c;以便服务器能够正确地将请求路由到相应的We…

【MiniCPM-V】win10本地部署OCR等性能测试

性能尝试 本地配置如下 --------------------------------------------------------------------------------------- | NVIDIA-SMI 546.80 Driver Version: 546.80 CUDA Version: 12.3 | |-----------------------------------------------------…

QQ名片满级会员装x助手HTML源码

源码介绍 QQ名片满级会员展示生成HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;保存素材去选择QQ个性名片-选择大图模板-把图上传照片墙即可 源码效果 源码下载 蓝奏云&#xff1a;http…

第18章-综合以上功能 基于stm32的智能小车(远程控制、避障、循迹) 基于stm32f103c8t6/HAL库/CubeMX/超详细,包含代码讲解和原理图

这个是全网最详细的STM32项目教学视频。 第一篇在这里: 视频在这里 STM32智能小车V3-STM32入门教程-openmv与STM32循迹小车-stm32f103c8t6-电赛 嵌入式学习 PID控制算法 编码器电机 跟随 第18章-综合以上功能 18-按键和app按钮切换功能 根据上面介绍&#xff0c;我们的模式可…

城市空气质量数据爬取分析可视化

城市空气质量数据爬取分析可视化 一、效果展示二、完整代码2.1 数据爬取代码2.2 数据分析代码一、效果展示 先来看一下数据情况以及可视化效果,本项目使用了pyecharts绘制了日历图、雷达图、折线图、柱状图、饼图和平行坐标系。完整代码附后: 数据如下: 日历图: 饼图: …

Nose,一款多功能灵活测试的Pythonl库

Nose库概述 Nose是一个用于Python单元测试的第三方库,旨在简化和扩展Python自带的unittest框架.它提供了更多功能和灵活性,使得编写和运行单元测试变得更加方便. 安装与使用 #首先安装Nose库:pip install nose使用 nose 运行单元测试的简单示例&#xff1a; 运行测试: imp…

Go源码--sync库(1)

简介 这篇主要介绍 sync.Once、sync.WaitGroup和sync.Mutex sync.Once once 顾名思义 只执行一次 废话不说 我们看源码 英文介绍直接略过了 感兴趣的建议读一读 获益匪浅 其结构体如下 Once 是一个严格只执行一次的object type Once struct {// 建议看下源码的注解&#xf…

【找出缺失的观测数据】python

思路&#xff1a; 主要在于分配剩余的部分分配问题 代码&#xff1a; class Solution:def missingRolls(self, rolls: List[int], mean: int, n: int) -> List[int]:m len(rolls)total_sum (n m) * meantoset total_sum - sum(rolls)# 检查 toset 是否在可能的范围内i…

堆和栈的特点以及在golang中的应用

堆和栈的特点&#xff1f;在golang中有哪些应用&#xff1f; 堆&#xff08;Heap&#xff09;和栈&#xff08;Stack&#xff09;是计算机内存管理中常见的两种数据结构&#xff0c;它们在内存分配和管理方面有着不同的特点&#xff1a; 堆&#xff08;Heap&#xff09;&#x…

亚马逊高效广告打法及数据优化,亚马逊高阶广告打法课

课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/89342733 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 001.1-亚马逊的广告漏斗和A9算法的升级变化.mp4 002.2-流量入口解析和广告的曝光机制.mp4 003.3-标签理论 .mp4 004.4-不同广告类…

影响所有股票、债券和ETF交易!一文看懂美国“T+1”结算新规

T1对投资者有何好处&#xff1f;有哪些风险&#xff1f;T1已经到来&#xff0c;T0还远吗&#xff1f; 美股将在本周迎来历史性时刻。 从当地时间5月28日开始&#xff0c;美股交易结算周期将由T2缩短至T1&#xff0c;即投资者当天卖出的股票&#xff0c;在交易后一个工作日就能…

蓝牙模块唤醒原理是怎样的?

随着科技的发展&#xff0c;蓝牙技术已经广泛应用于各种设备&#xff0c;如智能手机、平板电脑、智能手表等。蓝牙模块作为一种重要的通信手段&#xff0c;为我们的生活带来了极大的便利。然而&#xff0c;蓝牙模块并不仅仅是用于传输数据的工具&#xff0c;它还具有一项独特的…

eNSP学习——OSPF被动接口配置

目录 相关命令 1、配置接口IP地址 2、配置OSPF进程号、区域号以及网段宣告 3、配置被动接口 4、查看OSPF的邻居关系状态以及路由条目 原理概述 实验目的 实验步骤 实验内容 实验编址 具体步骤 1、基本配置 测试结果(仅提供一个) 2、搭建OSPF网络 3、配置被动接口…

LangChain之链的认识

Chain链 概述 为开发更复杂的应用程序&#xff0c;需要使用Chain来链接LangChain中的各个组件和功能&#xff0c;包括模型之间的链接以及模型与其他组件之间的链接。 链在内部把一系列的功能进行封装&#xff0c;而链的外部则又可以组合串联。 链其实可以被视为LangChain中的一…