linux系统编程2--网络编程
在linux系统编程中网络编程是使用socket(套接字),socket这个词可以表示很多概念:
在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP
地址+端口号”就称为socket。在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。socket本身有“插座”的意思,因此用来描述网络连接的一对一关系。
TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socket API,本节的主要内容是socket API。
1、预备知识
1)网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。网络数据流同样有大端小端之分,那么如何定义网络数据流的地址呢?发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。例如上一节的UDP段格式,地址0-1是16位的源端口号,如果这个端口号是1000(0x3e8),则地址0是0x03,地址1是0xe8,也就是先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe8。但是,如果发送主机是小端字节序的,这16位被解释成0xe803,而不是1000。因此,发送主机把1000填到发送缓冲区之前需要做字节序的转换。同样地,接收主机如果是小端字节序的,接到16位的源端口号也要做字节序的转换。如果主机是大端字节序的,发送和接收都不需要做转换。同理,32位的IP地址也要考虑网络字节序和主机字节序的问题。
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
h表示host,n表示network,l表示32位长整数,s表示16位短整数。
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
2)IP地址转换函数
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);
只能处理IPv4的ip地址,不可重入函数,注意参数是struct in_addr
3)sockaddr数据结构
strcut sockaddr 很多网络编程函数诞生早于IPv4协议,那时候都使用的是sockaddr结构体,为了向前兼容,现在sockaddr退化成了(void *)的作用,传递一个地址给函数,至于这个函数是sockaddr_in还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型

IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示
4)TCP/UDP对比
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接;
2、TCP提供可靠的服务,也就是说通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付;
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等);
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信;
5、TCP首部开销20字节;UDP的首部开销小,只有8字节;
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道;
5)端口号的作用
一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等,这些服务完全可以通过一个IP地址来实现。那么主机是怎么样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务关系是一对多的关系。
实际上主机是通过“IP地址+端口号”来区分不同的服务的。端口提供了一种访问通道,服务器一般都是通过知名端口号来识别的。例如对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69。
6)socket通信过程

7)相关api介绍
连接协议(socket):
函数原型:int socket(int domain, int type, int protocol);
参数1int domain:指明所使用的协议,通常为AF_INET,表示互联网协议族(TCP/IP协议族);
(AF_INET—IPv4因特网域、AF_INET6—IPv6因特网域、AF_UNIX—Unix域、AF_ROUTE—路由套接字、AF_KEY—密钥套接字、AF_UNSPEC—未指定)
参数2 int type:指定socket的类型;
(SOCK_STREAM:流式套接字提供可靠的、面向连接的通信流;使用TCP协议,保证了数据传输的正确性和顺序性;SOCK_DGRAM:数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,而且不保证是可靠的、无差错的。它使用UDP协议;SOCK_RAM:允许程序使用底层协议,原始套接字允许对底层协议如IP或ICMP进行直接访问,功能强大但使用不便,用于协议的开发)
参数3int protocol:通常赋值0;
(0:选择type类型对应的默认协议;IPPROTO_TCP—TCP协议;IPPROTO_UDP—UDP协议;IPPROTO_SCTP—SCTP协议;IPPROTO_TIPC—TIPC协议)
成功返回该socket的文件描述符,否则返回-1;
绑定IP地址和端口号(bind):
函数原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数1int sockfd:是一个socket描述符;
参数2const struct sockaddr *addr:结构体指针,包含协议族、端口号、IP地址等;
参数3socklen_t addrlen:结构体大小;
成功返回0,否则返回-1;
这里涉及到IP地址转换问题:我们人眼看到的是字符串,我们要把IP地址转换为网络能识别的格式:
int inet_aton(const char *straddr,struct in_addr *addrp); //字符串转网络格式
char* inet_ntoa(struct in_addr inaddr); //网络格式转字符串
监听设置函数(listen):
函数原型:int listen(int sockfd, int backlog);
参数1int sockfd:服务器端socket描述符;
参数2int backlog:指定在请求队列中允许的最大请求数;
成功返回0,否则返回-1;
服务器接收客户端连接(accept):
函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数1int sockfd:服务器端socket描述符;
参数2struct sockaddr *addr:返回已连接的客户端的协议地址;
参数3socklen_t *addrlen:客户端地址长度;
成功返回一个新的套接字描述符,即已连接的套接字描述符,否则返回-1;
客户端连接服务器(connect):
函数原型:int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数1int sockfd:目的服务器的socket描述符;
参数2const struct sockaddr *addr:服务器端的IP地址和端口号的地址结构体指针;
参数3socklen_t addrlen:地址长度;
成功返回0,否则返回-1;
数据收发:
函数原型:
1.ssize_t read(int fd, void *buf, size_t count); //读数据
2.ssize_t write(int fd, const void *buf, size_t count); //写数据
8)Socket服务器和客户端的开发步骤
服务器开发:1.创建套接字(socket)— 2.为套接字添加信息(IP地址和端口号)(bind)— 3.监听网络连接(listen)— 4.监听到有客户端接入,接受一个连接(accept)— 5.数据交互(read、write)— 6.关闭套接字,断开连接(close)
客户端开发:1.创建套接字(socket)— 2.连接服务器(connect)— 3.数据交互(read、write)— 4.关闭套接字,断开连接(close)
2、网络编程实操
1)简单服务器搭建
server.c代码如下:
#include <stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>int main()
{int s_fd,c_fd; struct sockaddr_in s_addr,c_addr; char readBuf[128] = {0};int n_read = 0;int length = sizeof(c_addr);char *retmes = "我是服务端"; memset(&s_addr,0,sizeof(s_addr));memset(&c_addr,0,sizeof(c_addr)); //1.int socket(int domain, int type, int protocol);s_fd = socket(AF_INET,SOCK_STREAM,0);if (s_fd == -1){perror("socket");exit(-1);} s_addr.sin_family = AF_INET; s_addr.sin_port = htons(6688); //int inet_aton(const char *cp, struct in_addr *inp);inet_aton("0.0.0.0",&s_addr.sin_addr);//2.int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);bind(s_fd,(struct sockaddr *)&s_addr,sizeof(s_addr)); //3.int listen(int sockfd, int backlog);listen(s_fd,128);  while(1){//4.int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&length);if (c_fd == -1){perror("accept");} //char *inet_ntoa(struct in_addr in);printf("ip=%s,port=%d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port)); //5.ssize_t read(int fd, void *buf, size_t count);n_read = read(c_fd,readBuf,128);if (n_read == -1){perror("read");}else{printf("get message:%d,%s\n",n_read,readBuf);}//6.ssize_t write(int fd, const void *buf, size_t count);write(c_fd,retmes,strlen(retmes)+1); } return 0;
}gcc server.c -o server.exe编译通过
2)简单客户端搭建
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//#include <linux/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>int main()
{int c_fd;struct sockaddr_in c_addr;char readBuf[128] = {0};int n_read = 0;char *mes = "我是客户端"; memset(&c_addr,0,sizeof(c_addr)); //1.int socket(int domain, int type, int protocol);c_fd = socket(AF_INET,SOCK_STREAM,0);if (c_fd == -1){perror("socket");exit(-1);} c_addr.sin_family = AF_INET;//uint16_t htons(uint16_t hostshort);c_addr.sin_port = htons(6688);//int inet_aton(const char *cp, struct in_addr *inp);inet_aton("192.168.43.253",&c_addr.sin_addr); //2.int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);if (connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){perror("coonnect");exit(-1);} //3.ssize_t write(int fd, const void *buf, size_t count);write(c_fd,mes,strlen(mes)+1); //4.ssize_t read(int fd, void *buf, size_t count);n_read = read(c_fd,readBuf,128);if (n_read == -1){perror("read");}else{printf("get message:%d,%s\n",n_read,readBuf);} return 0;
}gcc client.c -o client.exe编译通过
3)测试效果
先启动服务端server.exe,再启动客户端client.exe

服务器先接收到客户端的接入,把客户端IP打印出来,客户端再把其数据发送给服务器,服务器再回应客户端。
就这么个玩意儿,跟java,c#中的socket编程道理一样,过程一样,就是66666.
相关文章:
linux系统编程2--网络编程
在linux系统编程中网络编程是使用socket(套接字),socket这个词可以表示很多概念:在TCP/IP协议中,“IP地址TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址端口号”就称为socket。在TCP协议中&#…...
Allegro如何重命名光绘操作指导
Allegro如何重命名光绘操作指导 在做PCB设计的时候,光绘设置是输出生产文件必要的流程,设置好光绘之后,如何对光绘重新命名,如下图 如何把L1改成TOP,L6改成BOTTOM,具体操作步骤如下 点击Manufacture选择Artwork...
[PMLR 2018] Hyperbolic entailment cones for learning hierarchical embeddings
Contents IntroductionEntailment Cones in the Poincar BallConvex cones in a complete Riemannian manifoldAngular cones in the Poincar ballfour intuitive propertiesClosed form expression of the optimal ψ \psi...
2023春季露营投影怎么选?轻薄投影极米Z6X Pro值得推荐
近年来,露营经济在多重因素的共同助推下快速发展,精致露营的攻略开始占据小红书、微博、朋友圈等各类社交平台,吸引着更多用户种草并加入到露营大军中,而露营经济的强势“破圈”给家用智能投影带来了更多的发展契机。凭借着小巧的…...
收藏,核心期刊的投稿、审稿、出刊流程详解
学术期刊论文(核心和普刊)的发表流程总的来说其实是一样的,整个流程包括:1写作-2选择刊物-3投稿-4审稿-5返修或拒稿-6录用-7出刊-8上网检索。 其中1和2其实顺序是可以调换的,可以选择好刊物再写作,根据刊物…...
JVM类加载子系统
1、类加载子系统在内存结构中所处的位置通过内存结构图,我们先知道类加载子系统所处的位置,做到心中有图。2、类加载器作用类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。ClassLoader只负责cla…...
摄像头的镜头的几个知识点
1、镜头的组成及镜片的固定方式 摄像头的镜头结构主要分为镜身,透镜,变焦环,对焦环,光圈叶片,部分还有防抖系统.其中最重要的就是透镜,也叫镜片。镜片的主要原料是光学玻璃,玻璃&…...
分布式-分布式存储笔记
读写分离 什么时候需要读写分离 互联网大部分业务场景都是读多写少的,读和写的请求对比可能差了不止一个数量级。为了不让数据库的读成为业务瓶颈,同时也为了保证写库的成功率,一般会采用读写分离的技术来保证。 读写分离的实现是把访问的压…...
第十三届蓝桥杯国赛 C++ C 组 Java A 组 C 组 Python C 组 E 题——斐波那契数组(三语言代码AC)
目录1.斐波那契数组1.题目描述2.输入格式3.输出格式4.样例输入5.样例输出6.数据范围7.原题链接2.解题思路3.Ac_code1.Java2.C3.Python1.斐波那契数组 1.题目描述 如果数组 A(a0,a1,⋯.an−1)A(a_0,a_1,⋯.a_{n-1})A(a0,a1,⋯.an−1)满足以下条件, 就说它是一个斐波那契…...
多因子模型(MFM)
多因子模型(Muiti-Factor M: MFM)因子投资基础CAPM (资本资产定价模型)APT套利定价理论截面数据 & 时间序列数据 & 面板数据定价误差 α\alphaαalpha 出现的原因线性多因子模型Fama-French三因子模型三因子的计算公式利用alpha大小进行购买股票…...
django项目实战一(django+bootstrap实现增删改查)
目录 一、创建django项目 二、修改默认配置 三、配置数据库连接 四、创建表结构 五、在app当中创建静态文件 六、页面实战-部门管理 1、实现一个部门列表页面 2、实现新增部门页面 3、实现删除部门 4、实现部门编辑功能 七、模版的继承 1、创建模板layout.html 1&…...
graphsage解读
传统的图方法都是直推式(transductive)的,学习到的是结构固定的图模型,一旦有新的节点加入,便需要重新训练整个图网络,泛化性不强。GraphSAGE是归纳式(inductive)的,它学习一种映射:通过采样和聚合邻居节点…...
一文带你读懂Dockerfile
目录 一、概述 二、DockerFile构建过程解析 (一)Dockerfile内容基础知识 (二)Docker执行Dockerfile的大致流程 (三)总结 三、DockerFile常用保留字指令 四、案例 (一)自定义…...
用python实现对AES加密的视频数据流解密
密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法。 在做网络爬虫的时候,会遇到经过AES加密的数据,可以使用python来进行解密。 在做爬虫的时候,通常可以找到一个key,这个key是一个十六进制的一串字符,这传字符是解密的关键。所以对于…...
网络高可用方案
目录 1. 网络高可用 2. 高可用方案设计 2.1 方案一 堆叠 ha负载均衡模式 2.2 方案二 OSPF ha负载均衡模式 3. 高可用保障 1. 网络高可用 网络高可用,是指对于网络的核心部分或设备在设计上考虑冗余和备份,减少单点故障对整个网络的影响。其设计应…...
简单的认识 Vue(vue-cli安装、node安装、开发者工具)
Vue1、Vue 与其他框架的对比及特点1.1 Vue.js 是什么1.2 作者1.3 作用1.4 Vue 与其他框架的对比2、安装 Vue 的方法2.1 CDN 引入2.2 脚手架工具2.3 vue 开发者工具安装3、创建第一个实例4、理解 Vue 的 MVVM 模式5、数据双向绑定5.1 感受响应式实验总结1、Vue 与其他框架的对比…...
如何写一个 things3 client
Things3[1] 是一款苹果生态内的任务管理软件,是一家德国公司做的,非常好用。我前后尝试了众多任务管理软件,最终选定 things3,以后有机会会写文章介绍我是如何用 things3 来管理我的日常任务。本文主要介绍欧神写的 tli[2] 工具来…...
人工智能原理复习 | 命题逻辑和谓词演算
文章目录 一、前言二、命题逻辑三、谓词逻辑CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 数理逻辑思想的起源:莱布尼茨之梦。古典数理逻辑主要包括两部分:命题逻辑和谓词逻辑,命题逻辑又是谓词逻辑的一种简单情形。 逻辑研究的基本内容: 语法。语言部分:基…...
前端基础面试题:如何判断对象是否具有某属性?遍历数组的方法有哪些?
一、如何判断对象具有某属性? 如:let obj{name:zhangsan,age:21} 有以下方法 ( property 为属性名的变量,实际上是key,键名): 1. property in obj 效果如图: in 运算符 2. Reflect.has(obj, property)…...
Docker入门和安装教程
一、Docker入门简介 Docker 是一个基于GO语言开发的开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。 容器是完全使用沙箱机制,相互之间不会…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
