Linux C/C++ UDP Socket 网络通信

2023-05-16

Python微信订餐小程序课程视频

https://edu.csdn.net/course/detail/36074

Python实战量化交易理财系统

https://edu.csdn.net/course/detail/35475
昨晚 Vv 让我给她讲讲网络编程,于是我就傻乎乎的带她入了门…

以下内容为讲课时制作的笔记~

1. socket() 函数

1.1 头文件

复制代码
  • 1

#include

1.2 函数参数

示例:int socket(int domain, int type, int protocol){...}

  • domain:设置协议域(协议族)

    • AF_INET:IPV4
    • AF_INET6:IPV6
    • ⋯⋯\cdots

协议族决定了 socket 的地址类型,在通信中必须采用对应类型的地址

  • type:指定 socket 类型

    • SOCKET_STREAM:流式 socket,针对于面向连接的 TCP 服务应用
    • SOCKET_DGRAM:数据报式 socket,针对于无连接的 UDP 服务应用
    • ⋯⋯\cdots
  • protocal:指定协议

    • 000:自动选择第二个参数类型对应的传输协议
    • IPPROTO_TCP:TCP传输协议
    • IPPROTO_UDP:UDP传输协议
    • ⋯⋯\cdots

type 和 protocal 不能随意组合,如 SOCKET_STREAM 不能和 IPPROTO_UDP 组合

1.3 返回值

示例:int sock_fd = socket(AF_INET, SOCKET_DGRAM, 0);

  1. sock_fd = -1:套接字创建失败
  2. sock_fd = x(x >= 0):套接字创建成功,返回套接字的文件描述符(索引)

套接字描述符是一个整数类型的值。每个进程的进程空间里都有一个套接字描述符表,该表中存放着套接字描述符和套接字数据结构的对应关系。该表中有一个字段存放新创建的套接字的描述符,另一个字段存放套接字数据结构的地址,因此根据套接字描述符就可以找到其对应的套接字数据结构。每个进程在自己的进程空间里都有一个套接字描述符表但是套接字数据结构都是在操作系统的内核缓冲里。

1.4 Socket是什么?

socket是对TCP/IP协议簇的封装,它的出现只是使得程序员更方便地使用TCP/IP协议栈而已。socket本身并不是协议,它是应用层与TCP/IP协议族通信的中间软件抽象层,是一组调用接口(TCP/IP网络的API函数)

socket在哪里

2. bind()函数

2.1 sockaddr

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5

#include struct sockaddr{ sa\_family\_t sin_family; // 协议族 char sa_data[14]; // 14 个字节,包含套接字中的目标地址和目标端口信息 };

2.2 sockaddr_in

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

`#include // 或 #include
struct in_addr{
In_addr_t s_addr; // 32位 IPv4 地址
};

struct sockaddr_in{
sa_family_t sin_family; // 协议族
uint16_t sin_port; // 16位 TCP/UDP 端口号 (端口号最大是 65535 = 2^16 - 1)
struct in_addr; // 32位 IP 地址
char sin_zero[8]; // 不使用 (为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节)
};`

  • sin_port 和 sin_addr 都必须是网络字节序(NBO),一般可视化的数字都是主机字节序(HBO)。
  • sockaddr_in 和 sockaddr 是并列的结构,指向 sockaddr_in 的结构体的指针也可以指向 sockadd 的结构体,并代替它。

2.3 函数参数

示例:int bind(sock_fd, const struct sockaddr* address, socklen_t address_len);

  • sock_fd:套接字描述符
  • address:sockaddr结构指针,该结构中包含了要绑定的地址和端口号
  • address_len:address缓冲区的长度
  • socklen_t 即 unsigned int
  • sizeof 的返回值也是 unsigned int

2.4 返回值

示例:

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

// 绑定 ip port struct sockaddr\_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(9123); // htons 主机字节序转网络字节序 // 方法1: // INADDR\_ANY 是通配地址,即本机所有 ip 都绑定上。 INADDR\_ANY 转换过来就是0.0.0.0 inet\_pton(AF_INET, INADDR_ANY, &addr.sin_addr.s_addr); // 方法2: // inet\_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr\_in.sin\_addr.s\_addr。 addr.sin_addr.s_addr = inet\_addr("192.168.0.115"); int res = bind(sock_fd, (struct sockaddr *) &addr, sizeof(addr));

  • res = 0:绑定成功
  • res = -1:绑定失败

2.5 作用

将 addr 指向的 sockaddr 结构体中描述的一些属性(IP地址、端口号、地址簇)与 socket 套接字绑定,也叫给套接字命名。

调用 bind() 后,就为 socket 套接字关联了一个相应的地址与端口号,即发送到该地址该端口的数据可通过 socket 读取和使用。当然也可通过该 socket 发送数据到指定目的。

对于Server,bind()是必须要做的事情,服务器启动时需要绑定指定的端口来提供服务(以便于客户向指定的端口发送请求),对于服务器 socket 绑定地址,一般而言将 IP 地址赋值为 INADDR_ANY(该宏值为0),即无论发送到系统中的哪个 IP 地址(当服务器有多张网卡时会有多个 IP 地址)的请求都采用该 socket 来处理,而无需指定固定 IP。

对于 Client,一般而言无需主动调用 bind(),一切由操作系统来完成。在发送数据前,操作系统会为套接字随机分配一个可用的端口,同时将该套接字和本地地址信息绑定。

关于套接字更详细的使用,可参考:https://github.com/qiyu56/network/tree/master/udp

3. sendto() 函数

3.1 函数参数

示例:int sendto(int sock_fd, const void *buf, int len, int flags, const struct sockaddr *address, socklen_t address_len);

  • sock_fd:套接字描述符

  • void *buf:UDP 数据报缓存区(包含待发送数据)

    1. void* 指针可以指向任意类型的数据:
    复制代码
    
    • 1
    • 2
    • 3void *p; int *a; p = a; // a = (int *)p;
    1. UDP 数据报缓存区:
    1. sendto 把数据放在 sendbuf(缓冲区),通知操作系统来取

    2. 操作系统在适当的时候过来取数据,并发到网络
      这意味着:存入数据和发送数据存在时间差(异步的),如果存入数据太快太多,缓冲区会满。缓冲区满的处理

    3. 知道缓冲区有剩余空间(阻塞)

    4. 新发送的数据没有存入缓冲区(直接丢掉)
      丢包对 UDP 来说是很正常,在使用 UDP 时就应该允许丢包

  • len:UDP数据报的长度

  • flags:调用方式标志位(一般设置为 000,先不掌握)

  • sockaddr *address:sockaddr结构指针,该结构中包含了要发送的地址和端口号

  • address_len:address缓冲区的长度

  • socklen_t 即 unsigned int
  • sizeof 的返回值也是 unsigned int

3.2 返回值

示例:

复制代码
  • 1
  • 2
  • 3

char buf[128] = ""; fgets(buf, sizeof(buf) , stdin); int res = sendto(sock_fd , buf , strlen(buf) , 0, (struct sockaddr *) &server_addr, sizeof(server_addr));

  • res = x:发送成功,xxx 为发送出去的字符数
  • res = -1:发送失败

3.3 作用

把 UDP 数据报发给指定地址。

4. revcfrom() 函数

4.1 函数参数

示例:recvfrom(int socke_fd, const void *buf, int len, int flags, struct sockaddr *address, socklen_t *address_len)

  • sock_fd:套接字描述符

  • void *buf:UDP 数据报缓存区(包含所接收的数据)

    1. UDP 数据报缓存区:
    1. 操作系统不停把从网络上接收数据,缓存在 recvbuf(缓冲区) 里
    2. recvfrom从缓存区里接收数据
      这意味着:不论你是否去取数据,操作总是把数据收下来存好,recfrom是从recvbuf里取走现成的数据,如果不及时取走,则缓冲区会满。缓冲区满的处理:
    • 新的数据不被接收
    • 删除缓冲区里的现有的数据,存放新的数据。
  • len:UDP数据报的长度

  • flags:调用方式标志位(一般设置为 000,先不掌握)

  • sockaddr *address:sockaddr结构指针,该结构中包含了发送方的地址和端口号(可以为 NULL)

  • address_len:socklen_t 指针,指向了 address 结构体的长度(可以为 NULL)

4.2 返回值

示例:

复制代码
  • 1
  • 2

char buf[128] = ""; int recv_len = recvfrom(sock_fd, buf, sizeof(buf), 0, (struct sockaddr*)&client_addr, &client_len);

  • recv_len = x:接收成功,xxx 为接收到的字符数
  • res = -1:接收失败

4.3 作用

接收发送方的网络数据。

5. 服务器代码与客户端代码

Server.cpp

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

`#include
#include
#include
#include
#include
using namespace std;

int main(int argc , char *argv[]){
cout << “Server:\n”;
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(sock_fd < 0) {
perror(“socket 创建失败”);
return 0;
}
cout << “socket 创建成功!\n”;
// 绑定 ip port
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9123);
// inet_pton(AF_INET, “192.168.0.111”, &addr.sin_addr.s_addr);
addr.sin_addr.s_addr = inet_addr(“192.168.0.115”); //INADDR_ANY 通配地址,即本机所有 ip 都绑定上。 INADDR_ANY 转换过来就是0.0.0.0
int res = bind(sock_fd, (struct sockaddr *) &addr, sizeof(addr));
if(res < 0) {
perror(“绑定失败”);
close(sock_fd);
return 0;
}
cout << “socket 绑定(命名)成功!\n”;
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
while(1){

char buf[128] = “”;
int recv_len = recvfrom(sock_fd, buf, sizeof(buf), 0, (struct sockaddr*)&client_addr, &client_len);
printf(“来自 ip 地址为 %s 端口号为 %d 的信息:%s 信息的总长度为 %d\n” , inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buf, recv_len);
sendto(sock_fd, buf, recv_len, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
}
close(sock_fd);
return 0;
}`

Client.cpp

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

`#include
#include
#include
#include
#include
using namespace std;
int main(int argc, char *argv[]){
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(9123); // 服务器端口
inet_pton(AF_INET, “192.168.0.115”, &server_addr.sin_addr.s_addr);

int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(sock_fd < 0)
perror("");

while(1){
char buf[128] = “”;
cin.getline(buf , sizeof(buf));
int res = sendto(sock_fd , buf , strlen(buf) , 0, (struct sockaddr *) &server_addr, sizeof(server_addr));
char read_buf[128] = “”;
recvfrom(sock_fd, read_buf, sizeof(read_buf), 0, NULL, NULL);
printf(“共发送 %d 个字符数\n” , res);
}
close(sock_fd);
return 0;
}`

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux C/C++ UDP Socket 网络通信 的相关文章

随机推荐

  • 【企业微信】获取token & 发送应用消息

    企业微信获取token 存入redis 设置时长2小时 amp amp 发送企业应用消息接口 1 常量类 span class token keyword package span span class token namespace co
  • 学习笔记--HTTP-字段总结(一)-与传输实体相关的报文字段总结

    目录 一 概述 二 介绍一些常用字段 三 传输实体的一些属性 1 传输的数据类型 2 实体的语言类型和编码 3 编码类型 四 文件类型和压缩编码字段 1 Accept 2 Content Type 3 Accept Encoding 4 C
  • C/C++ 去掉宏定义__FILE__路径

    一 问题 在日志模块中往往带着文件信息 xff0c 有的源文件是加载其他路径下的源文件 xff0c 但是不想让别人看到文件路径信息 xff0c 只显示源文件的名字和行数即可 如下图所示 xff0c 有烦人的相对路径 二 解决方案 自定义一个
  • C语言提高(一)

    C语言提高 CS和BS的区别函数封装和数组形参退化为指针数据类型本质变量的本质内存分区模型全局区以文字常量区为例分析全局区 栈区堆区 函数的调用模型函数调用变量传递分析静态局部变量的使用栈地址的生长方向堆地址的生长方向内存的存放方向 以数组
  • ROS Gazebo(三):启动gazebo/URDF

    打开Gazebo的方式主要有两种 xff1a rosrun 和 roslaunch 1 启动ROS节点 启动ROS节点 bring up 机器人的标准工具是roslaunch 打开一个空的Gazebo世界命令如下 xff1a roslaun
  • Windows与Ubuntu之间通过网线传输文件

    一 windows与Ubuntu之间网线直连搭建局域网 把网线连好后 xff0c 在两个系统中做以下设置 Windows下的配置 右键右下角的网络图标 xff08 或者右键网络 属性 xff09 更改适配器设置 以太网 右键属性 TCP I
  • Jetson TX2——CAN口的使用

    Jetson TX2 之CAN口的使用 TX2上有2个CAN控制器 xff0c CAN控制器需要通过CAN收发器连接到物理总线上 具体参阅原理图和相关技术参考手册 下载地址 xff1a https developer nvidia com
  • Jetson TX2——串口的使用(TTL-RS485)

    Jetson TX2之串口的使用 xff08 TTL RS485 xff09 TX2串口设备 TX2 有5个 UARTs 到主连接器 其中UART3 用于 WLAN BT 有关 UARTs 的典型任务 请参见下表 查看可用串口设备 xff1
  • 面试题知识点全纪录---容器

    注意 xff1a 该博客仅是本人对掌握知识的测试 xff0c 具体内容请移步guide哥网站 xff01 xff01 xff01 https snailclimb gitee io javaguide 链接 JAVA集合框架 https w
  • 高并发-消息队列

    一 消息队列 消息队列在分布式系统中主要是为了解耦和削峰 什么是消息队列 我们可以把消息队列看作是一个存放消息的容器 xff0c 当我们需要使用消息的时候 xff0c 直接从容器中取出消息供自己使用即可 消息队列是分布式系统中重要的组件之一
  • Ublox-M8N GPS接收机UBX协议解析

    Ublox M8N GPS接收机UBX协议解析 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • Java清空List方法

    1 用list clear 方法清空list xff1b 用此方法 xff0c 其它引用该list的值也会变成空 2 用list 61 null来清空list 3 new ArrayList 来清空list
  • fastjson用java转json时间的格式化

    一 项目中需求遇到需要接收其他应用数据 xff0c 通过 64 RequestBody注解接收参数后 xff0c 到本地利用fastJson把json格式化 需要注意一下几点 xff1a 需要在调用JSON toJSONString 的时候
  • 工具类里面调用service接口或者mapper接口

    我们在开发中经常会遇到需要将一些频繁进行的操作抽取封装到工具类中 xff0c springboot不支持注入静态属性 所以在工具类中使用 64 Autowired或者其他注解自动注入会失败 xff0c 才用如下方法这可以避免注入失败 spa
  • windows下停止【kill】nginx命令

    杀死nginx taskkill fi 34 imagename eq nginx EXE 34 f taskkill f t im nginx exe stop bat taskkill f t im nginx exe pause
  • 基本类型对应的缓冲池

    基本类型对应的缓冲池如下 xff1a boolean values true and false all byte values short values between 128 and 127 int values between 128
  • 记录JVM中Eden区、Survivor from区和Survivor to区及Minor GC和Major GC的理解

    仅做学习笔记 JVM中Eden区 Survivor from区和Survivor to区 本文主要根据 深入理解JVM 中内存回收策略 xff0c 主要关注如下五个方面 xff1a 1 xff1a Eden区分配 2 xff1a 大对象直接
  • ubuntu下修改python默认版本的方法

    Ubuntu安装之后会面临多个python版本共存的问题 xff08 python2和python3 xff09 xff0c 但是有时候安装其他库的时候会安装在默认的python版本环境下 xff08 比如 xff0c 通常默认版本是pyt
  • C++:C语言实现HTTP的GET和POST请求

    https www cnblogs com diligenceday p 6255788 html
  • Linux C/C++ UDP Socket 网络通信

    Python微信订餐小程序课程视频 https edu csdn net course detail 36074 Python实战量化交易理财系统 https edu csdn net course detail 35475 昨晚 Vv 让