Linux网络编程:Socket套接字编程

文章目录:

一:定义和流程分析

1.定义

2.流程分析 

3.网络字节序

二:相关函数 

IP地址转换函数inet_pton inet_ntop(本地字节序 网络字节序)

socket函数(创建一个套接字)

bind函数(给socket绑定一个服务器地址结构(IP+port))

listen函数(设置最大连接数或者说能同时进行三次握手的最大连接数监听上限)

accept函数(阻塞监听等待客户端建立连接, 成功的话返回一个与客户端成功连接的socket文件描述符)

connect函数(使用现有的socket与服务器建立连接)

三:服务器模型和客户端模型的实现 

Server服务器的实现

Client客户端的实现


一:定义和流程分析

1.定义

定义:一个文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现)在通信过程中, 套接字一定是成对出现的一种文件类型,伪文件,不占用存储空间,可进行IO操作,可间接看做文件描述符使Socket本身有“插座”的意思在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件管道, 套接字, 块设备, 字符设备;套接字: 一个fd可以索引读写两个缓冲区;

2.流程分析 

 

socket():创建一个套接字, 用fd索引bind():绑定IP和portlisten():设置监听上限(同时与Server建立连接数)accpet():阻塞监听客户端连接(传入一个上面创建的套接字, 传出一个连接的套接字)在客户端中的connect()中绑定IP和port,并建立连接(阻塞)

3.网络字节序

小端法:(pc本地存储)	高位存高地址。低位存低地址。	int a = 0x12345678
大端法:(网络存储)	高位存低地址。低位存高地址。htonl --> 本地--》 网络 (IP)			192.168.1.11 --> string --> atoi --> int --> htonl --> 网络字节序
htons --> 本地--》 网络 (port)
ntohl --> 网络--》 本地(IP)
ntohs --> 网络--》 本地(Port)

用库函数做网络字节序和主机字节序的转换

#include<arpa/inet.h>
uint32_t htonl(uint32_t hostlong);			//主要针对IP
uint16_t htons(uint16_t hostshort);			//主要针对port
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

二:相关函数 

IP地址转换函数inet_pton inet_ntop(本地字节序 网络字节序)

由于如192.168.45.2这种的IP地址为点分十进制表示,需要转化为uint32_t型,有现成的函数(IPv4和IPv6都可以转换) 

//本地字节序(string IP) ---> 网络字节序
int inet_pton(int af, const char *src, void *dst);		                   af:AF_INET、AF_INET6src:传入,IP地址(点分十进制)dst:传出,转换后的 网络字节序的 IP地址。 返回值:成功: 1异常: 0, 说明src指向的不是一个有效的ip地址。失败:-1//网络字节序 ---> 本地字节序(string IP)
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);	af:AF_INET、AF_INET6src: 网络字节序IP地址dst:本地字节序(string IP)size: dst 的大小。返回值: 成功:dst、失败:NULL

socket函数(创建一个套接字)

#include <sys/socket.h>int socket(int domain, int type, int protocol);		创建一个 套接字domain指定使用的协议(IPv4或IPv6)AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址AF_INET6 与上面类似,不过是来用IPv6的地址AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用type指定数据传输协议(流式或报式)SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序指定代表协议(一般默认传0)protocol: 0 流式以TCP为代表;报式以UDP为代表;返回值:返回指向新创建的socket的文件描述符成功:返回新套接字所对应文件描述符fd失败:返回-1并设置errno;

bind函数(给socket绑定一个服务器地址结构(IP+port))

#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);		给socket绑定一个 地址结构 (IP+port)sockfd: socket文件描述符struct sockaddr_in servaddr;addr.sin_family = AF_INET;addr.sin_port = htons(8888);addr.sin_addr.s_addr = htonl(INADDR_ANY);addr: 构造出IP地址加端口号传入参数(struct sockaddr *)&addraddrlen: sizeof(addr) 地址结构的大小返回值:成功:0失败:返回-1, 设置errno

listen函数(设置最大连接数或者说能同时进行三次握手的最大连接数监听上限)

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>int listen(int sockfd, int backlog);        //设置同时与服务器建立连接的上限数(同时进行3次握手的客户端数量)sockfd:socket文件描述符backlog:上限数值。最大值 128排队建立3次握手队列和刚刚建立3次握手队列的链接数和返回值:成功:0失败:-1 errno	

accept函数(阻塞监听等待客户端建立连接, 成功的话返回一个与客户端成功连接的socket文件描述符)

#include <sys/types.h> 		/* See NOTES */
#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);sockfd:socket文件描述符addr:成功与Sever建立连接的那个**客户端**的地址结构;传出参数,返回链接客户端地址信息(IP地址+端口号)addrlen:传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小	    
​	    socklen_t clit_addr_len=sizeof(addr);
​	    入: 传入addr的大小;
​	    出: 客户端addr的实际大小;返回值:    
​	    成功: 返回能与客户端进行通信的socket对应的文件描述符;
​	    失败: 返回-1并设置errno;//我们的服务器程序结构是这样的
while (1) {cliaddr_len = sizeof(cliaddr);connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);n = read(connfd, buf, MAXLINE);......close(connfd);
}

connect函数(使用现有的socket与服务器建立连接)

#include <sys/types.h> 					/* See NOTES */
#include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);sockdf:socket文件描述符struct sockaddr_in srv_addr;		// 服务器地址结构srv_addr.sin_family = AF_INET;srv_addr.sin_port = 9527 	跟服务器bind时设定的 port 完全一致。inet_pton(AF_INET, "服务器的IP地址",&srv_adrr.sin_addr.s_addr);addr:传入参数,指定服务器端地址信息,含IP地址和端口号addrlen:传入参数,服务器地址结构的长度sizeof(addr)大小返回值:​	成功返回0;
​	    失败返回-1并设置errno;如果不使用`bind()`函数绑定客户端的地址结构, 会采用**"隐式绑定"**;

三:服务器模型和客户端模型的实现 

Server服务器的实现

server:1. socket()	创建socket2. bind()	绑定服务器地址结构3. listen()	设置监听上限4. accept()	阻塞监听客户端连接5. read(fd)	读socket获取客户端数据6. 小--大写	toupper()7. write(fd)8. close();

代码逻辑

#include <stdio.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>#define SERV_PORT 9527					//端口号int main(int argc, char *argv[]){int link_fd=0;						//建立连接的socket文件描述符int connect_fd=0					//用于通信的文件描述符int ret=0;							//用于检查是否出错char buf[BUFSIZ];					//缓冲区char client_IP[1024]				//存入客户端IP字符串int num=0;							//读出的字节数/*服务器端地址结构*/struct sockaddr_in serv_addr;                   	 // 定义服务器地址结构 和 客户端地址结构serv_addr.sin_family=AF_INET;                    // IPv4serv_addr.sin_port=htons(SERV_PORT);             // 转为网络字节序的 端口号serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);     // 获取本机任意有效IP/*成功与服务器建立连接的客户端地址结构*/struct sockaddr_in clint_addr;socklen_t clint_addr_len=sizeof(clint_addr);    	 // 获取客户端地址结构大小/*1.socket函数:创建用于建立连接的socket,返回的文件描述符存入link_fd*///IPv4,按照顺序基于字节流的连接,指定代表协议link_fd=socket(AF_INET,SOCK_STREAM,0);		if(link_fd==-1)sys_err("socket error");/*2.bind函数:绑定服务器端的socket绑定地址结构(IP+port)*///socket文件描述符link_fd,IP地址加端口号ret=bind(link_fd,(const struct sockaddr*)&serv_addr,sizeof(serv_addr));if(ret==-1)sys_err("bind error");/*3.listen函数:设定监听(连接)上线*/ret=listen(link_fd,128); if(ret==-1)sys_err("listen error");/*4.accept函数:阻塞等待客户端建立连接*///文件描述符,与Sever建立连接的客户端的地址结构,返回真正接收到地址结构体的大小connect_fd=accept(link_fd,(	struct sockaddr*)&clint_addr,&clint_addr_len);    if(connect_fd==-1)sys_err("accept error");/*建立连接后打印客户端的IP和端口号    获取客户端地址结构*/printf("client IP:%s,client port:%d",  												//`client_IP`是前面定义的客户端IP字符串的缓冲区, 大小为1024           inet_ntop(AF_INET,&clint_addr.sin_addr.s_addr,client_IP,sizeof(client_IP)),		//网络字节序 ---> 本地字节序ntohs(clint_addr.sin_port)														//根据accept传出参数,获取客户端 ip 和 port);           /*业务逻辑*/while(1){//5. read(fd)	读socket获取客户端数据num=read(connect_fd,buf,sizeof(buf));    // 读客户端数据write(STDOUT_FILENO,buf,num);            // 写到屏幕查看//6. 小--大写	toupper()for(i=0;i<num;i++)                       // 小写 -- 大写buf[i]=toupper(buf[i]);//7. write(fd)write(connect_fd,buf,num);               // 将大写,写回给客户端sleep(1);}//8. close()close(connect_fd);close(link_fd);return 0;
}

测试命令 

`nc 127.0.0.1 9527`        //脑残命令: 向这个服务发送信息并打印回执

Client客户端的实现

client:1. socket()	创建socket2. connect();	与服务器建立连接3. write()	写数据到 socket4. read()	读转换后的数据。5. 显示读取结果6. close()

代码逻辑

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>#define SERV_PORT 9527/*错误处理函数*/
void sys_err(const char* str){perror(str);exit(1);
}int main(int argc, char *argv[])){int client_fd=0;int ret=0;int num=0;int cnt=10;char buf[BUFSIZ];//connect的参数2填入服务器的文件描述符!struct sockaddr_in serv_addr;serv_addr.sin_family=AF_INET;serv_addr.sin_port=htons(SERV_PORT);// 本地字节序(string IP) ---> 网络字节序inet_pton(AF_INET,"127.0.0.1",(void*)&serv_addr.sin_addr.s_addr);/*1. 创建socket():客户端直接创建用于连接的套接字即可*/client_fd=socket(AF_INET,SOCK_STREAM,0);if(client_fd==-1)sys_err("socket error");/*2. connect():将客户端套接字与服务器地址结构连接起来*/ret=connect(client_fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));if(ret!=0)sys_err("connect error");//业务逻辑while(--cnt){//3. write()	写数据到 socketwrite(client_fd,"fuckyou\n",8);//4. read()	读转换后的数据。num=read(client_fd,buf,sizeof(buf));//5. 显示读取结果write(STDOUT_FILENO,buf,num);sleep(1);}//6. close()close(client_fd);return 0;
}

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

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

相关文章

企业数据库遭到360后缀勒索病毒攻击,360勒索病毒解密

在当今数字化时代&#xff0c;企业的数据安全变得尤为重要。随着数字化办公的推进&#xff0c;企业的生产运行效率得到了很大提升&#xff0c;然而针对网络安全威胁&#xff0c;企业也开始慢慢引起重视。近期&#xff0c;我们收到很多企业的求助&#xff0c;企业的服务器遭到了…

go 协程并发数控制

错误的写法&#xff1a; 这里的<-ch 是为了从channel 中读取 数据&#xff0c;为了不使channel通道被写满&#xff0c;阻塞 go 协程数的创建。但是请注意&#xff0c;go workForDraw(v, &wg) 是不阻塞后续的<-ch 执行的&#xff0c;所以就一直go workForDraw(v, &…

Find My资讯|苹果Vision Pro开发者需将设备配对 AirTag

最近苹果Vision Pro获开发者申请&#xff0c;苹果要求获批的申请者使用 Measure and Fit 应用确认合适的佩戴尺寸&#xff0c;并会根据申请者提交的信息&#xff0c;定制不同的 Vision Pro 开发者套件&#xff0c;以便于契合申请者的面部特征&#xff0c;提供更好的佩戴体验。 …

iPhone 15受益:骁龙8 Gen 3可能缺席部分安卓旗舰机

明年一批领先的安卓手机的性能可能与今年的机型非常相似。硅成本的上涨可能是原因。 你可以想象&#xff0c;2024年许多最好的手机都会在Snapdragon 8 Gen 3上运行&#xff0c;这是高通公司针对移动设备的顶级芯片系统的更新&#xff0c;尚未宣布。然而&#xff0c;来自中国的…

基于libevent的tcp服务器

libevent使用教程_evutil_make_socket_nonblocking_易方达蓝筹的博客-CSDN博客 一、准备 centos7下安装libevent库 yum install libevent yum install -y libevent-devel 二、代码 server.cpp /** You need libevent2 to compile this piece of code Please see: http://li…

多种方法实现 Nginx 隐藏式跳转(隐式URL,即浏览器 URL 跳转后保持不变)

多种方法实现 Nginx 隐藏式跳转(隐式URL,即浏览器 URL 跳转后保持不变)。 一个新项目,后端使用 PHP 实现,前端不做路由,提供一个模板,由后端路由控制。 Route::get(pages/{name}, [\App\Http\Controllers\ResourceController::class, getResourceVersion])

独立站SEO是什么意思?自主网站SEO的含义?

什么是独立站SEO优化&#xff1f;自建站搜索引擎优化是指什么&#xff1f; 独立站SEO&#xff0c;作为网络营销的重要一环&#xff0c;正在逐渐引起人们的关注。在当今数字化时代&#xff0c;独立站已经成为许多企业、个人宣传推广的首选平台之一。那么&#xff0c;究竟什么是…

【c语言】文件操作

朋友们&#xff0c;大家好&#xff0c;今天分享给大家的是文件操作的相关知识&#xff0c;跟着我一起学习吧&#xff01;&#xff01; &#x1f388;什么是文件 磁盘上的文件是文件。 但是在程序设计中&#xff0c;我们一般谈的文件有两种&#xff1a;程序文件、数据文件 程序文…

如何用输入函数为数组赋值

在编写程序时我们经常使用数组&#xff0c;而数组的大小可能是很大的但是我们并不需要为每个元素都自己赋值&#xff0c;我们可能会自定义输入数组元素个数&#xff0c;我们应该如何实现通过输入函数为数组赋值呢&#xff1f; 目录 第一种&#xff1a; 第二种&#xff1a; 第一…

Floyd(多源汇最短路)

Floyd求最短路 给定一个 n 个点 m 条边的有向图&#xff0c;图中可能存在重边和自环&#xff0c;边权可能为负数。 再给定 k 个询问&#xff0c;每个询问包含两个整数 x 和 y&#xff0c;表示查询从点 x 到点 y 的最短距离&#xff0c;如果路径不存在&#xff0c;则输出 impo…

深入理解python虚拟机:程序执行的载体——栈帧

栈帧&#xff08;Stack Frame&#xff09;是 Python 虚拟机中程序执行的载体之一&#xff0c;也是 Python 中的一种执行上下文。每当 Python 执行一个函数或方法时&#xff0c;都会创建一个栈帧来表示当前的函数调用&#xff0c;并将其压入一个称为调用栈&#xff08;Call Stac…

分布式 - 服务器Nginx:一小时入门系列之负载均衡

文章目录 1. 负载均衡2. 负载均衡策略1. 轮询策略2. 最小连接策略3. IP 哈希策略4. 哈希策略5. 加权轮询策略 1. 负载均衡 跨多个应用程序实例的负载平衡是一种常用技术&#xff0c;用于优化资源利用率、最大化吞吐量、减少延迟和确保容错配置。‎使用 nginx 作为非常有效的HT…

高速PCB设计初学者容易犯的一些错误

高速PCB设计初学者容易犯的一些错误 硬件开发人员设计PCB时&#xff0c;应力求所设计PCB满足以下条件&#xff1a; PCB应首先满足规定的电气性能指标&#xff0c;原则上时电流越大&#xff0c;走线越宽&#xff1b;电压越大&#xff0c;线与线之间的距离越大&#xff1b;PCB应…

下一代计算:嵌入AI的云/雾/边缘/量子计算

计算系统在过去几十年中推动了计算机科学的发展&#xff0c;现在已成为企业世界的核心&#xff0c;提供基于云计算、雾计算、边缘计算、无服务器计算和量子计算的服务。现代计算系统解决了现实世界中许多需要低延迟和低响应时间的问题。这有助于全球各地的青年才俊创办初创企业…

【Kubernetes】Kubernetes的Pod控制器

Pod控制器 一、Pod 控制器的概念1. Pod 控制器及其功用2. Pod 控制器有多种类型2.1 ReplicaSet2.2 Deployment2.3 DaemonSet2.4 StatefulSet2.5 Job2.6 Cronjob 3. Pod 与控制器之间的关系 二、Pod 控制器的使用1. Deployment2. SatefulSet2.1 为什么要有headless&#xff1f;2…

【数据结构OJ题】设计循环队列

原题链接&#xff1a;https://leetcode.cn/problems/design-circular-queue/ 1. 题目描述 2. 循环队列的概念和结构 为充分利用向量空间&#xff0c;克服"假溢出"现象的方法是&#xff1a;将向量空间想象为一个首尾相接的圆环&#xff0c;并称这种向量为循环向量。…

职业学院物联网实训室建设方案

一、概述 1.1专业背景 物联网&#xff08;Internet of Things&#xff09;被称为继计算机、互联网之后世界信息产业第三次浪潮&#xff0c;它并非一个全新的技术领域&#xff0c;而是现代信息技术发展到一定阶段后出现的一种聚合性应用与技术提升&#xff0c;是随着传感网、通…

【仿写tomcat】七、项目结构优化以及代码开源

仿写tomcat 项目结构开源地址 项目结构 到目前为止&#xff0c;博主的仿写tomcat就告一段落了&#xff0c;后续有时间了还会继续补充功能&#xff0c;现在的项目结构如下。 在保证功能的前提下作出的改动有&#xff1a; 将各个类中的参数统一成了Config类&#xff0c;通过对…

Midjourney Prompt 提示词速查表 v5.2

Midjourney 最新的版本更新正不断推出令人兴奋的新功能。这虽然不断扩展了我们的AI绘图工具箱&#xff0c;但有时也会让我们难以掌握所有实际可以使用的功能和参数。 针对此问题, 小编整理了 "Midjourney Prompt 提示词速查表"&#xff0c;这是一个非常方便的 Midjo…