Linux网络编程(二)Socket编程

Socket编程

一、网络套接字概念:socket

一个文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现。)

在通信过程中, 套接字一定是成对出现的。

套接字通讯原理

二、网络字节序和主机字节序的转换函数(ip和端口)

小端法:(pc本地存储、Intel架构)	高位存高地址。地位存低地址。	int a = 0x12345678

大端法:(网络存储、IDM公司)	高位存低地址。地位存高地址。

#include <arpa/inet.h>

	htonl --> 本地(host)--》网络(net) (IP)			192.168.1.11 --> string --> atoi --> int --> htonl --> 网络字节序

	htons --> 本地--》网络 (port)

	ntohl --> 网络--》 本地(IP)

	ntohs --> 网络--》 本地(Port)
	
	h-->host;n-->network;l-->32位长整数; s-->16位短整数

三、IP地址转换函数(inet_pton):

int inet_pton(int af, const char *src, void *dst);		本地字节序(string IP) ---> 网络字节序

	af:AF_INET、AF_INET6

	src:传入,IP地址(点分十进制)

	dst:传出,转换后的 网络字节序的 IP地址。 

	返回值:

		成功: 1

		异常: 0, 说明src指向的不是一个有效的ip地址。

		失败:-1

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);	网络字节序(二进制) ---> 本地字节序(string IP)

	af:AF_INET、AF_INET6

	src: 网络字节序IP地址

	dst:本地字节序(string IP)--缓冲区

	size: dst 的大小。缓冲区大小

	返回值: 成功:dst。 	

		失败:NULL

四、sockaddr地址结构: IP + port --> 在网络环境中唯一标识一个进程。

sockaddr数据结构

man 7 ip命令

man_7_ip

//定义
struct sockaddr_in addr;      // #include<arpa/inet.h>

//初始化
addr.sin_family = AF_INET/AF_INET6				
addr.sin_port = htons(9527);
	int dst;
	inet_pton(AF_INET, "192.157.22.45", (void *)&dst);//点分十进制(字符串类型)转为网络字节序
addr.sin_addr.s_addr = dst;
【*】addr.sin_addr.s_addr = htonl(INADDR_ANY);		INADDR_ANY取出本系统中有效的任意IP地址,二进制类型。转为网络字节序

//使用
bind(fd, (struct sockaddr *)&addr, size);

五、socket函数:

socketApi

socket连续

#include <sys/socket.h>

int socket(int domain, int type, int protocol);		创建一个 套接字

	domain:AF_INET、AF_INET6、AF_UNIX

	type:SOCK_STREAM(TCP)、SOCK_DGRAM(UDP)

	protocol: 0 

	返回值:

		成功: 新套接字所对应文件描述符

		失败: -1 errno 可使用perror();

 #include <arpa/inet.h>

 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);		给socket绑定一个 地址结构 (IP+port)

	sockfd: socket 函数返回值

		struct sockaddr_in addr;

		addr.sin_family = AF_INET;

		addr.sin_port = htons(8888);

		addr.sin_addr.s_addr = htonl(INADDR_ANY);

	addr: 传入参数(struct sockaddr *)&addr

	addrlen: sizeof(addr) 地址结构的大小。

	返回值:

		成功:0

		失败:-1 errno

int listen(int sockfd, int backlog);		设置同时与服务器建立连接的上限数。(同时进行3次握手的客户端数量)

	sockfd: socket 函数返回值

	backlog:上限数值。最大值 128.


	返回值:

		成功:0

		失败:-1 errno	

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);	阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的socket文件描述符。
第2卷---系统函数
	sockfd: socket 函数返回值

	addr:传出参数。成功与服务器建立连接的那个客户端的地址结构(IP+port)

		socklen_t clit_addr_len = sizeof(addr);

	addrlen:传入传出。 &clit_addr_len

		 入:addr的大小。 出:客户端addr实际大小。

	返回值:

		成功:能与客户端进行数据通信的 socket 对应的文件描述。

		失败: -1 , errno

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);	  使用现有的 socket 与服务器建立连接

	sockfd: 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:传入参数。服务器的地址结构

	addrlen:服务器的地址结构的大小

	返回值:

		成功:0

		失败:-1 errno

	如果不使用bind绑定客户端地址结构, 采用"隐式绑定".

六、TCP通信流程分析:

server:
	1. socket()	创建socket

	2. bind()	绑定服务器地址结构

	3. listen()	设置监听上限

	4. accept()	阻塞监听客户端连接

	5. read(fd)	读socket获取客户端数据

	6. 小--大写	toupper()

	7. write(fd)

	8. close();

client:

	1. socket()	创建socket

	2. connect();	与服务器建立连接
	
	3. 从终端读取数据

	4. write()	写数据到 socket

	5. read()	读转换后的数据。

	6. 显示读取结果

	7. close()

示例:TCP通信完成客户端和服务端

//server.c

#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

#define SERV_PORT 54321

void sys_error(const char *str)
{
	perror(str);
	exit(1);
}

int main(int argc, char *argv[])
{
	int ret = 0;
	int lfd = 0, cfd = 0;
	char buf[BUFSIZ], clit_ip[BUFSIZ];//BUFSIZ 表示4096

	struct sockaddr_in serv_addr,clit_addr;
	socklen_t clit_addr_len;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERV_PORT);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	lfd = socket(AF_INET,SOCK_STREAM,0);	//创建套接字
	if(lfd == -1)
	{
		sys_error("socket error");	
	}	

	ret = bind(lfd,(struct sockaddr *)&serv_addr, sizeof(serv_addr));//绑定本地ip和端口
	if(ret == -1)
	{
		sys_error("bind error");
	}

	ret = listen(lfd,30);//设置套接字的最大连接数
	if(ret == -1)
	{
		sys_error("listen error");
	}	

	clit_addr_len = sizeof(clit_addr);
	cfd = accept(lfd,(struct sockaddr *)&clit_addr, &clit_addr_len);//设置阻塞监听,返回连接socket描述符
	if(cfd == -1)
	{
		sys_error("accept error");
	}
	printf("client ip:%s,port:%d\n",//打印客户端ip和port
		inet_ntop(AF_INET,&clit_addr.sin_addr.s_addr,clit_ip,sizeof(clit_ip)),
		ntohs(clit_addr.sin_port)
		);
	

	while(1)
	{
		ret = read(cfd, buf, sizeof(buf));
		write(STDOUT_FILENO, buf, ret);
		if(ret == -1)
		{
			sys_error("read error");
		}
		for(int i=0; i<ret; i++)
			buf[i] = toupper(buf[i]);
		write(cfd, buf, ret);
	}

	close(lfd);
	close(cfd);

	return 0;
}
///client.c
#include <stdio.h> 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define SERV_PORT 54321

void sys_err(const char* str)
{
	perror(str);
	exit(1);
}

int main(int argc, char* argv[])
{
	int cfd = 0, ret = 0;
	char buf[BUFSIZ];
	struct sockaddr_in serv_addr;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERV_PORT);
	inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);


	cfd = socket(AF_INET, SOCK_STREAM, 0);	
	if(cfd == -1)
	{
		sys_err("socket error");
	}

	//连接
	ret = connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));	
	if(ret == -1)
	{
		sys_err("connect error");
	}
	while(1)	
	{
		ret = read(STDIN_FILENO, buf, sizeof(buf));
		//写
		ret = write(cfd,buf,ret);	
		if(ret == -1)
		{
			sys_err("wirte error");
		}
		ret = read(cfd, buf, sizeof(buf));
		write(STDOUT_FILENO, buf, ret);	
	}
	close(cfd);
	return 0;
}

七、错误处理函数:

封装目的: 

	在 server.c 编程过程中突出逻辑,将出错处理与逻辑分开,可以直接跳转man手册。


【wrap.c】								【wrap.h】


存放网络通信相关常用 自定义函数						存放 网络通信相关常用 自定义函数原型(声明)。

命名方式:系统调用函数首字符大写, 方便查看man手册
	
	  如:Listen()、Accept();

函数功能:调用系统调用函数,处理出错场景。

在 server.c 和 client.c 中调用 自定义函数

联合编译 server.c 和 wrap.c 生成 server

	 client.c 和 wrap.c 生成 client

readn:
	读 N 个字节
	
readline:
	读一行

read 函数的返回值:

	1. > 0 实际读到的字节数

	2. = 0 已经读到结尾(对端已经关闭)【 !重 !点 !】

	3. -1 应进一步判断errno的值:

		errno = EAGAIN or EWOULDBLOCK: 设置了非阻塞方式 读。 没有数据到达。 

		errno = EINTR 慢速系统调用被 中断。

		errno = “其他情况” 异常。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营第二十一天|530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

530.二叉搜索树的最小绝对差 题目链接&#xff1a;530.二叉搜索树的最小绝对差 文档讲解&#xff1a;代码随想录 状态&#xff1a;还可以 思路&#xff1a;使用中序遍历来遍历二叉搜索树。在中序遍历过程中&#xff0c;比较当前节点和前驱节点的值&#xff0c;更新最小差值。返…

中国四大高原矢量示意图分享

我们在《中国地势三级阶梯示意图分享》一文中&#xff0c;为你分享了中国三级阶梯示意图的矢量文件。 现在&#xff0c;我们再为你分享中国四大高原的矢量示意图文件&#xff0c;你可以在文末查看文件的领取方法。 我国四大高原是如何划分的&#xff1f; 中国四大高原分别为…

你觉得前端开发人员有必要学习Rust吗?

有必要&#xff0c;为什么&#xff1f; 1. 性能优势 Rust能编译成高效的机器码&#xff0c;这对于需要高性能处理的前端项目尤其有利。例如&#xff0c;处理复杂的数据计算或图像处理时&#xff0c;Rust可以提供接近于C/C的性能&#xff0c;同时避免诸如内存泄漏或缓冲区溢出…

2024中国网络安全产品用户调查报告(发布版)

自2020年始&#xff0c;人类进入了21世纪的第二个十年&#xff0c;全球进入了百年未有之大变局&#xff0c;新十年的开始即被新冠疫情逆转了全球化发展的历程&#xff0c;而至2022年3月俄乌战争又突然爆发&#xff0c;紧接着2023年7月“巴以冲突"皱起&#xff0c;世界快速…

LabVIEW进行负载测试

本文介绍了如何使用LabVIEW进行负载测试&#xff0c;通过一个具体案例详细讲解了测试系统的组成、工作原理和实现方法。系统采用先进的硬件和软件架构&#xff0c;结合LabVIEW的强大功能&#xff0c;成功实现了对设备的高效负载测试&#xff0c;确保了系统的可靠性和性能。 项…

LogicFlow 学习笔记——1. 初步使用 LogicFlow

什么是 LogicFlow LogicFlow 是一个开源的前端流程图编辑器和工作流引擎&#xff0c;旨在帮助开发者和业务人员在网页端创建、编辑和管理复杂的业务流程和工作流。它提供了一个直观的界面和强大的功能&#xff0c;使得设计和管理工作流变得更加高效和便捷。 官网地址&#xff…

时间轴、流程类时间轴绘制

效果图 可控制是否绘制在中间控制绘制的线条是否为虚线控制第一条数据圆顶部线条和最后一条数据圆底部线条是否绘制 除了gif图片展示的属性&#xff0c;还可以控制圆的大小颜色、圆是否有上和左偏移、线条颜色等属性 除了通用的时间轴绘制&#xff0c;我们还可以通过改变绘制…

国外创意二维码应用:飞利浦旧物翻新活动,传播可持续性消费的重要性!

你知道去年有超过1000万件礼物被扔进了垃圾场吗? 这些被丢弃的物品中有许多仍在使用&#xff0c;飞利浦希望改变这种浪费现象。 去年的地球日&#xff0c;飞利浦策划了一场名为“Better than New” 的二维码营销活动。他们发布了一个视频&#xff0c;通过这个短视频将所有最终…

微信小程序组件传值

虽然微信小程序是比较轻量的&#xff0c;但是还是拥有组件的 这是文件的基本目录 我们的代码基本都在pages和components文件夹中 在component中创建组件 在component中 &#xff0c;创建一个目录 我创建了一个 head目录 用于配置头部信息 我在这里创建了 一个头部组件&…

Vue基础知识:异步DOM更新是什么?$nextTick是什么?到底应该如何使用。什么是同步?什么是异步?

要先了解异步dom更新是什么就必须先了解&#xff0c;什么是同步&#xff1f;什么是异步&#xff1f; 1.什么是同步&#xff1f;什么是异步&#xff1f; 同步&#xff08;Synchronous&#xff09;&#xff1a; 同步操作是按照代码的顺序执行的&#xff0c;每个操作都必须等待上…

NiceGUI:让Python变身为Web应用开发大师的神器

简介 NiceGUI是一个易于使用的基于Python的UI框架&#xff0c;可以在您的Web浏览器中使用。您可以创建按钮、对话框、Markdown、3D场景、图表等等。 NiceGUI开源支持较好&#xff0c;代码更新频率较高&#xff0c;目前已经更新至: V1.4.26。 适用场景 NiceGUI非常适用于各种…

为什么 JavaScript 在国外逐渐用于前端+后端开发

这个问题其实没人能给出可证伪的结论&#xff0c;那不如干脆给一个感性的答案: 因为阿里“不争气”。 确切的说&#xff0c;因为阿里的nodejs团队没卷赢&#xff0c;至少暂时还没卷赢&#xff0c;没拿到真正有价值的业务场景&#xff0c;做出真正有说服力的案例项目。刚好我有…

【微信小程序】开发环境配置

目录 小程序的标准开发模式&#xff1a; 注册小程序的开发账号 安装开发者工具 下载 设置外观和代理 第一个小程序 -- 创建小程序项目 查看项目效果 第一种&#xff1a;在模拟器上查看项目效果 项目的基本组成结构 小程序代码的构成 app.json文件 project.config…

8.2 Go 导入与导出

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

手机短信验证码登录

用户需求&#xff1a; 1、用户使用手机号和短信验证码登录系统 2、未注册过的手机号再登录时实现自动注册 3、新注册的账号只有7天的使用时间&#xff0c;过期后不允许进行登录 功能需求&#xff1a; 登录页面设计 图1.手机号登录 【验证码登录】规则说明&#xff1a; …

各类电机数学模型相关公式总结 —— 集成芯片驱动

0、背景技术概述 永磁直流电机&#xff08;PMDC&#xff09;、永磁同步电机&#xff08;PMSM&#xff09;、无刷直流电机&#xff08;BLDC&#xff09;以及混合式两相步进电机在小功率应用场景中多采用集成芯片驱动&#xff08;如二合一、三合一驱动芯片&#xff09;的原因主要…

Linux C语言:函数的基本用法及传参

一、函数的基本用法 1、main函数 int main(int argc, const char * argv[]) { printf("Hello world\n"); return 0; }数据类型 函数名称 (参数) { //.... return 表达式 } 2、函数 函数是一个完成特定功能的代码模块&#xff0c;其程序代码独立&#xff0c;通常要…

使用Python修改word文档中的表格

使用Python编辑word文档中的表格 介绍效果代码代码解析 介绍 使用python修改word文档中的表格。 效果 修改前的word文档&#xff1a; 注意红框中的表格。 修改后的word文档&#xff1a; 表格内容已经修改。 代码 from docx import Document# 加载现有的Word文档 doc D…

electron基础使用

安装以及运行 当前node版本18&#xff0c;按照官网提供操作&#xff0c;npm init进行初始化操作&#xff0c;将index.js修改为main.js&#xff0c;执行npm install --save-dev electron。&#xff08;这里我挂梯子下载成功了。&#xff09;&#xff0c;添加如下代码至package.…

AI办公自动化:用Kimi批量在Excel文件名中加入日期

工作任务&#xff1a;在一个文件夹中所有的Excel文件后面加上一个日期 在Kimi中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;写一个Python脚本&#xff0c;具体步骤如下&#xff1a; 打开文件夹&#xff1a;F:\AI自媒体内容\AI行业数据分析\投融资 读取里面所…