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

news2024/12/25 2:23:19

文章目录:

一:定义和流程分析

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和port

listen():设置监听上限(同时与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_INET6
	src:传入,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_INET6
	src: 网络字节序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 *)&addr

    addrlen: 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()	创建socket

	2. 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;                    // IPv4
		serv_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()	创建socket

	2. connect();	与服务器建立连接

	3. write()	写数据到 socket

	4. 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()	写数据到 socket
			write(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.coloradmin.cn/o/900171.html

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

相关文章

使用线性回归模型优化权重:探索数据拟合的基础

文章目录 前言一、示例代码二、示例代码解读1.线性回归模型2.MSE损失函数3.优化过程4.结果解读 总结 前言 在机器学习和数据科学中&#xff0c;线性回归是一种常见而重要的方法。本文将以一个简单的代码示例为基础&#xff0c;介绍线性回归的基本原理和应用。将使用Python和Nu…

安卓框架中的常见问题汇总

目录 1.安卓操作系统的组件结构图如下 2.问题汇总 1.安卓操作系统的组件结构图如下 2.问题汇总 问题1&#xff1a;安卓框架中的库和应用程序框架之间什么关系&#xff1f; 在安卓系统中&#xff0c;应用程序框架层&#xff08;Application Framework&#xff09;是核心应用程…

迈向通用听觉人工智能!清华电子系、火山语音携手推出认知导向的听觉大语言模型SALMONN

日前&#xff0c;清华大学电子工程系与火山语音团队携手合作&#xff0c;推出认知导向的开源听觉大语言模型SALMONN (Speech Audio Language Music Open Neural Network)。 大语言模型 SALMONN LOGO 相较于仅仅支持语音输入或非语音音频输入的其他大模型&#xff0c;SALMONN对…

Python爬虫的scrapy的学习(学习于b站尚硅谷)

目录 一、scrapy  1. scrapy的安装  &#xff08;1&#xff09;什么是scrapy  &#xff08;2&#xff09;scrapy的安装 2. scrapy的基本使用  &#xff08;1&#xff09;scrap的使用步骤  &#xff08;2&#xff09;代码的演示 3. scrapy之58同城项目结构和基本方法&…

面试最常问的数组转树,树转数组 c++ web框架paozhu实现

刚毕业同学&#xff0c;找工作常被问 二维数组转树&#xff0c;树转二维数组 需要支持无限层级实现&#xff0c;如果你了解这个语言那么实现起来还要一番思考 c web框架 paozhu使用 需要实现数据库表数据到前台菜单实现&#xff0c;就是这种功能 二维数组转树&#xff0c;树转…

学习笔记:Opencv实现拉普拉斯图像锐化算法

2023.8.19 为了在暑假内实现深度学习的进阶学习&#xff0c;Copy大神的代码&#xff0c;记录学习日常 图像锐化的百科&#xff1a; 图像锐化算法-sharpen_lemonHe_的博客-CSDN博客 在环境配置中要配置opencv&#xff1a; pip install opencv-contrib-python Code and lena.png…

【模拟集成电路】反馈系统——基础到进阶(一)

【模拟集成电路】反馈系统——基础到进阶 前言1 概述2 反馈电路特性2.1增益灵敏度降低2.2 终端阻抗变化2.3 带宽拓展2.4 非线性减小 3 放大器分类4 反馈检测和返回机制4.1 按照检测物理量分类4.2 按照检测拓扑连接分类 5 反馈结构分析6 二端口方法7 波特方法6 麦德布鲁克方法 前…

Go中的有限状态机FSM的详细介绍 _

1、FSM简介 1.1 有限状态机的定义 有限状态机&#xff08;Finite State Machine&#xff0c;FSM&#xff09;是一种数学模型&#xff0c;用于描述系统在不同状态下的行为和转移条件。 状态机有三个组成部分&#xff1a;状态&#xff08;State&#xff09;、事件&#xff08;…

认识Spring框架

目录 1.了解Spring框架 2.了解Spring的体系结构 3.认识Spring家族 4.实现第一个Spring入门程序 1.了解Spring框架 1.什么是Spring框架&#xff1f; Spring是一个轻量级的控制反转&#xff08;IoC&#xff09;和面向切面的容器框架。 关键词概念解释&#xff1a; 1.轻量级…

2023国赛数学建模思路 - 案例:ID3-决策树分类算法

文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模…

2028量产?兰博基尼首款纯电车型Lanzador亮相,双电机四驱跨界GT

经过多次预热之后&#xff0c;兰博基尼的首款纯电车型Lanzador终于在8月19日正式亮相。这款车以较完整的面貌出现在大众面前&#xff0c;将于2028年开始正式量产。虽然Lanzador仍是一个暂定名字&#xff0c;但它来自西班牙语&#xff0c;意为“投手”、“发射器”和“推动者”&…

C++笔记之注册的含义

C笔记之注册的含义 code review! 文章目录 C笔记之注册的含义1.注册对象到Qt的信号槽系统中2.注册函数到Qt的元对象系统中元对象系统例1例2 3.注册自定义类型到C STL容器中4.将函数指针传递给另一个类&#xff0c;注册回调函数class ICallback存在的意义例1&#xff0c;用于说…

专业课只考2门,计算机学硕最低分290的江苏院校

南京工业大学 考研难度&#xff08;☆&#xff09; 内容&#xff1a;23考情概况&#xff08;拟录取和复试分析&#xff09;、专业目录、23复试详情、各专业考情分析。 正文1332字&#xff0c;预计阅读&#xff1a;3分钟。 2023考情概况 南京工业大学计算机相关各专业复试和…

Intellij中直接运行ts配置:run configuration for typescript

在Intellij中可以借助插件run configuration for typescript直接运行typescript&#xff1a; run configuration for typescript插件本质还是依赖于 ts-node 来运行&#xff0c;只是其可以帮助我们自动配置好 ts-node 运行参数&#xff0c;简化使用。 第一步&#xff1a;安装…

uniapp配置添加阿里巴巴图标icon流程步骤

文章目录 下载复制文件到项目文件夹里项目配置目录结构显示图标 下载 阿里巴巴icon官网 https://www.iconfont.cn/ 复制文件到项目文件夹里 项目配置目录结构 显示图标

带你了解建堆的时间复杂度

目录 用向上调整建堆的时间复杂度 1.向上调整建堆的时间复杂度O(N*logN) 2.数学论证 3.相关代码 用向下调整建堆的时间复杂度 1.建堆的时间复杂度为O(N) 2.数学论证 3.相关代码 完结撒花✿✿ヽ(▽)ノ✿✿ 博主建议:面试的时候可能会被面试官问到建堆时间复杂度的证明过…

安卓手机的充电原理

安卓手机的充电原理是通过充电器将交流电转换为直流电&#xff0c;然后通过USB接口传输到手机电池中。手机电池的充电过程分为三个阶段&#xff1a;涓流充电、恒流充电和恒压充电。 充电动画 涓流充电是用来先对完全放电的电池单元进行预充&#xff08;恢复性充电&#xff09…

pdf 转 word

pdf 转 word 一、思路 直接调用LibreOffice 命令进行文档转换的命令行工具 使用的前系统中必须已经安装了 libreofficelibreoffice已翻译的用户界面语言包: 中文 (简体)libreoffice离线帮助文档: 中文 (简体)上传字体 重点&#xff1a;重点&#xff1a;重点&#xff1a; 亲…

蓝光眼镜有效吗?科研团队:无法证明防蓝光镜片可以减少视力伤害

8 月 19 日消息&#xff0c;本次由墨尔本大学、莫纳什大学和伦敦城市大学联合进行的科研团队&#xff0c;对来自 6个国家和地区的 17 项已发表的研究进行了深入研究。他们的研究发现&#xff0c;无法证明防蓝光镜片能够减少眼睛的视力伤害或改善佩戴者的睡眠质量等功效。 这项研…

【网络教程】如何获取阿里云盘的refresh_token

文章目录 获取阿里云盘的refresh_token 获取阿里云盘的refresh_token 这里在Edge浏览器上进行演示首先我们需要登入我们的阿里云盘然后按F12进入开发者模式&#xff0c;在菜单栏选择应用程序&#xff0c;然后在左边菜单找到 本地存储 下的 https://www.aliyundrive.com 这个域…