09.计算机网络——套接字编程
文章目录
- 网络字节序
- socket编程
- socket 常见API
- sockaddr结构
- UDP编程
- 创建socket
- 绑定socket
- sendto发送数据
- recvform接收数据
- 关闭socket
- TCP编程
- 创建socket
- 绑定socket
- listen监听套接字
- accept服务端接收连接套接字
- connect客户端连接套接字
- send发送数据
- recv接收数据
- 关闭socket
- 工具
- netstat
- telnet
- 地址转换函数
- socket编程注意细节
- 代码案例
网络字节序
内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网络数据流同样有大端小端之分。
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据。为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
-
h表示host,n表示network,l表示32位长整数,s表示16位短整数。
-
htonl表示将32位的长整数从主机字节序转换为网络字节序。
-
ntohl表示将32位的长整数从网络字节序转换为主机字节序。
socket编程
socket套接字通常指的是封装了ip和port的结构体,其是网络编程中的一种通信机制,支持TCP/IP的网络通信的基本操作单元,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。
socket 常见API
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
sockaddr结构
套接字分类:
- 域间套接字 —— 本地通信
- 原始套接字 —— 允许绕过传输层,直接跟底层打交道,主要用来写一些工具。
- 网络套接字 —— 网络通信
理论上是三种应用场景,对应的应该是三套接口,但是Linux设计套接字的时候不想设计过多的接口,所以Linux将所有的接口进行了统一,只使用sockaddr结构体来描述这三种场景。 但是真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址。
UDP编程
创建socket
#include <sys/types.h>
#include <sys/socket.h>
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
//参数
domain:指定网络层的协议AF_INT: 使用ipv4版本的ip协议AF_INT6:使用ipv6版本的ip协议AF_UNIX:本地通信
type: 指定套接字的类型SOCK_DGRAM :使用UDP数据报套接字SOCK_STREAM:使用TCP字节流套接字
protocol:指定使用的协议0:使用套接字类型对应的默认协议
绑定socket
int bind(int socket, const struct sockaddr* address,socklen_t address_len);*
//参数
sockfd: socket函数返回的套接字描述符
addr: 地址信息结构体成员,struct sockaddr 是一个通用地址信息结构
address_len:地址信息结构的长度
sendto发送数据
ssize_t sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);
//参数
sockfd: 套接字描述符
buf: 要发送的数据
len: 发送数据的长度
flags: 0-阻塞发送
dest_addr: 目标主机的地址信息结构体
addrlen: 目标主机地址信息结构体的长度
//返回值
成功返回发送的字节数量,失败返回-1
recvform接收数据
ssize_t recvfrom(int sockfd, void* buf, size_t len, int flags,struct sockaddr* src_addr, socklen_t* addrlen);
//参数
sockfd: 套接字描述符
buf: 将数据接收到buf当中
len: buf的最大接收能力
flags: 0-阻塞接收
src_addr: 数据来源的主机地址信息结构体
addrlen: 输入输出型参数
//返回值
成功则返回实际接收到的字符数,失败返回-1,错误原因会存于errno中
关闭socket
close(int sockfd);
//sockfd: 套接字描述符
TCP编程
创建socket
#include <sys/types.h>
#include <sys/socket.h>
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
//参数
domain:指定网络层的协议AF_INT: 使用ipv4版本的ip协议AF_INT6:使用ipv6版本的ip协议AF_UNIX:本地通信
type: 指定套接字的类型SOCK_DGRAM :使用UDP数据报套接字SOCK_STREAM:使用TCP字节流套接字
protocol:指定使用的协议0:使用套接字类型对应的默认协议
//返回值:
socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,程序可以像读写文件一样用read/write在网络上收发数据;调用出错则返回-1
绑定socket
int bind(int socket, const struct sockaddr* address,socklen_t address_len);*
//参数
sockfd: socket函数返回的套接字描述符
addr: 地址信息结构体成员,struct sockaddr 是一个通用地址信息结构
address_len:地址信息结构的长度
listen监听套接字
//listen()声明sockfd处于监听状态
int listen(int sockfd, int backlog);
//参数
sockfd: 套接字描述符
backlog:已完成连接队列的大小
//返回值:成功:0失败:-1
当客户端和服务端进行三次握手的时候会存在两种状态:连接还未建立和连接已建立,此时操作系统内核中就会存在两个队列:未完成连接队列和已完成连接队列。当完成三次握手后会由未完成连接队列放到已完成连接队列,而backlog就是已完成连接队列的大小,backlog影响了服务端并发接收连接的能力。
accept服务端接收连接套接字
//从已经完成连接队列中获取已经完成三次握手的连接,没有连接时,调用accept会阻塞等待。
int accept(int sockfd, struct sockaddr* addr, socklen_t * addrlen);
//参数
sockfd:套接字描述符(listen_sockfd)
addr:输出型参数,保存客户端地址信息结构(客户端IP,客户端的端口)
addrlen:输入输出参数,传入缓冲区的大小,传出客户端地址信息结构的长度
//返回值成功:返回新连接的套接字描述符失败:返回-1
三次握手的时候是对listen_sockfd进行操作,当调用accept()会在Tcp服务端内部创建一个新的套接字new_sockfd,三次握手之后的数据收发都是多new_sockfd进行操作。
connect客户端连接套接字
//客户端需要调用connect()连接服务器
int connect(int sockfd, const struct sockaddr * addr,socklen_t addrlen);
//参数
sockfd:套接字描述符(listen_sockfd)
addr:服务端地址信息结构(服务端IP,服务端的端口)
addrlen:服务端地址信息结构的长度
//返回值成功:返回0小于0,连接失败
send发送数据
ssize_t send(int sockfd, const void * buf, size_t len, int flags);//参数
sockfd:套接字描述符(new_sockfd)
buf:待要发送的数据
len:发送数据的长度
flags:0:阻塞发送MSG_OOB:发送带外数据,在紧急情况下所产生的数据,会越过前面进行排队的数据优先进行发送。//返回值大于0:返回发送的字节数量-1:发送失败
recv接收数据
ssize_t recv(int sockfd, void * buf, size_t len, int flags);//参数
sockfd:套接字描述符(new_sockfd)
buf:将接收的数据放到buf
len:buf的最大接收能力
flags:0:阻塞发送;如果客户端没有发送数据,调用recv会阻塞//返回值大于0:正常接收了多少字节数据等于0:对端将连接关闭了小于0:接受失败
关闭socket
close(int sockfd);
//sockfd: 套接字描述符
工具
netstat
netstat -anp | grep [端口号]
- 查看端口的使用情况
telnet
- 进入cmd,使用telnet模仿TCP三次握手建立连接,在cmd窗口输入 “tenlet + 公网IP + 端口号” 即可模拟测试
地址转换函数
sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP 地址,但是我们通常用点分十进制的字符串表示IP 地址,以下函数可以在字符串表示 和in_addr表示之间转换
字符串转in_addr的函数:
in_addr转字符串的函数:
inet_ntoa函数把这个返回结果放到了静态存储区,这个时候不需要我们手动进行释放。
socket编程注意细节
- 客户端没有必要调用bind()固定一个端口号,否则如果在同一台机器上启动多个客户端,就会出现端口号被占用导致不能正确建立连接。
- 服务器也不是必须调用bind(),但如果服务器不调用bind(), 内核会自动给服务器分配监听端口, 每次启动服务器时端口号都不一样,客户端要连接服务器就会遇到麻烦。
- 多进程的客户端代码和单进程是一样的,父进程负责accept,子进程负责数据的接收和发送,若子进程一直不退出,则父进程一直在等待,永远无法接收新连接,可以使用自定义信号处理方式将SIGCHLD信号重新定义,当子进程退出发出SIGCHLD信号时,父进程则对子进程的资源进行回收。
- 建立好了tcp连接之后,我们就可以把得到的fd当作文件描述符来使用,也可以使用read和 write函数进行读写。
代码案例
UDP案例
UDP · 程序员Jared/Linux - 码云 - 开源中国 (gitee.com)
TCP案例
TCP · 程序员Jared/Linux - 码云 - 开源中国 (gitee.com)
相关文章:

09.计算机网络——套接字编程
文章目录 网络字节序socket编程socket 常见APIsockaddr结构 UDP编程创建socket绑定socketsendto发送数据recvform接收数据关闭socket TCP编程创建socket绑定socketlisten监听套接字accept服务端接收连接套接字connect客户端连接套接字send发送数据recv接收数据关闭socket 工具n…...

Data Structure, Algorithm,and Applications in C++
在学习这本书进阶内容之前,我们可以跟着它的第一章部分再巩固和复习。本书由Sartaj Sahni撰写,由王立柱和刘志红翻译。全书通俗易懂,内容丰富,是巩固C内容的不二选择。希望本文对各位有所帮助。 目录 1.函数与参数 1.1.传值参数…...

Apipost使用教程
Apipost是一款集API调试、生成文档、Mock、测试于一体的协同工具。单个工具可以同时满足接口测试、生成/分享文档、Mock、流程测试等功能,还有超实用的多人多角色间实时协作的功能。将前端、后端、测试三种角色串联起来,从而实现工作流程无缝衔接、提高研…...
如何使用Python进行服务器管理和自动化操作?
使用Python进行服务器管理和自动化操作可以极大地简化和提高日常管理任务的效率。下面是一些常见的方法和工具: SSH库:使用Python的paramiko库可以通过SSH协议连接到服务器,执行命令、上传文件和下载文件等操作。 例如,使用para…...

Kafka-partition和消费者的关系
Kafka-partition 目录概述需求: 设计思路实现思路分析1.Kafka-partition2.消费者数量小于分区数量3. 拓展实现 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a…...

使用克拉默法则进行三点定圆(二维)
目录 1.二维圆2.python代码3.计算结果 本文由CSDN点云侠原创,爬虫网站请自重。 1.二维圆 已知不共线的三个点,设其坐标为 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)、 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)、 ( x 3 , y 3 ) (x_3,y_3) (x3,y3)…...

【Java】Java多线程编程基础
文章目录 1. 进程与线程1.1 进程与线程的基本认识1.1.1 进程(Process)1.1.2 线程(Thread) 1.2 为什么会有线程1.2.1 以看视频为例 2. 多线程实现2.1 Thread类实现多线程2.2 Runnable接口实现多线程2.3 Callable接口实现多线程2.3 …...
FFmpeg-4.2.4的去logo源码分析
1.源码 libavfilter/vf_delogo.c 2.源码分析 /** 去logo算法, 函数的参数解释如下: w: 输入图像的宽度 h: 输入图像的高度 logo_x: 标志区域左上角的x坐标 logo_y: 标志区域左上角的y坐标 logo_w: 标志的宽度 logo_h: 标志的高度 band: 处理区域周围的带宽大小 show: 是否在…...

深度学习(一)
目录 一、特征工程的作用 二、深度学习的应用 三、得分函数 四、损失函数 五、前向传播 六、反向传播 一、特征工程的作用 数据特征决定了模型的上限预处理和特征提取是最核心的算法与参数选择决定了如何逼近这个上限 二、深度学习的应用 无人驾驶人脸识别分辨率重构 深…...

Stream API将对象中的某一字段取出转换为list或数组
List<DevicePartMaintain> devicePartMaintainList devicePartMaintainMapper.selectDevicePartMaintainByMitId(mitId);所有id转换为List 要使用Stream流获取devicePartMaintainList中所有的id,您可以使用stream()方法将列表转换为流,然后使用…...

什么是Java中的JVM(Java虚拟机)?
JVM(Java虚拟机)是Java平台的核心组件之一,是一个用于执行Java字节码的虚拟计算机。Java源代码经过编译器编译,生成字节码文件(.class文件),然后由JVM来解释和执行这些字节码。JVM负责将字节码翻…...

springboot + redis + 注解 + 拦截器 实现接口幂等性校验
一、概念 幂等是一个数学与计算机学概念,在数学中某一元运算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同。在计算机中编程中,一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。 幂等函数或幂等方法是…...

PLC编程:关键在于模拟操作流程和实现控制
PLC编程的核心是通过程序描述流程,完成控制过程。因此,掌握PLC编程语言和基本功能实现是必要的。 PLC语言主要分为梯形图、语句和功能图。梯形图适合基本逻辑描述,语句表用于数据处理,相对较难理解。步进式功能图的状态函数描述很…...

List的各种排序
目录 Collections.sort对list进行排序 对象中某个属性进行排序 通过比较器进行比较 JAVA8特性Stream流进行排序 Stream升降序组合使用 Collections.sort对list进行排序 public static void main(String[] args) {List<Integer> list new ArrayList<>();list…...

在自定义数据集上微调Alpaca和LLaMA
本文将介绍使用LoRa在本地机器上微调Alpaca和LLaMA,我们将介绍在特定数据集上对Alpaca LoRa进行微调的整个过程,本文将涵盖数据处理、模型训练和使用流行的自然语言处理库(如Transformers和hugs Face)进行评估。此外还将介绍如何使用grado应用程序部署和…...
Python 实现接口类的两种方式+邮件提醒+动态导入模块+反射(参考Django中间件源码)
实现抽象类的两种方式 方式一 from abc import ABCMeta from abc import abstractmethodclass BaseMessage(metaclassABCMeta):abstractmethoddef send(self,subject,body,to,name):pass 方式二 class BaseMessage(object):def send(self, subject, body, to, name):raise …...

Solr原理剖析
一、简介 Solr是一个高性能、基于Lucene的全文检索服务器。Solr对Lucene进行了扩展,提供了比Lucene更为丰富的查询语言,并实现了强大的全文检索功能、高亮显示、动态集群,具有高度的可扩展性。同时从Solr 4.0版本开始,支持SolrCl…...
解决 “无法将 ‘npm‘ 项识别为 cmdlet、函数、脚本文件或可运行程序的名称“ 错误的方法
系列文章目录 文章目录 系列文章目录前言一、错误原因:二、解决方法:三、注意事项:总结 前言 在使用 npm 进行前端项目开发时,有时会遇到错误信息 “无法将 ‘npm’ 项识别为 cmdlet、函数、脚本文件或可运行程序的名称”&#x…...
Python 电商API 开发最佳实践
一、简介 当你打卡了一家北京最具有地中海特色的餐厅,当我们在餐厅点餐时,服务员会给我们一份菜单,菜单上列出了所有可供选择的菜品和饮料。我们可以在菜单上选择我们想要的食物和饮料,然后告诉服务员我们的选择。服务员会根据我…...

JAVA基础-集合(List与Map)
目录 引言 一,Collection集合 1.1,List接口 1.1.1,ArrayList 1.1.1.1,ArrayList的add()添加方法 1.1.1.2,ArrayList的remove()删除方法 1.1.1.3,ArrayList的contai…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...