Linux网络编程(二)Socket编程

news2024/11/15 11:13:59

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.coloradmin.cn/o/1814421.html

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

相关文章

戎码翼龙NG-EDR白皮书

NG-EDR 很轻 内核轻量不卡机&#xff01; ◆ 戎码翼龙AI原生NG-EDR具备强大的数据采集能力&#xff0c;涵盖了MITRE ATT&CK框架下的终端数据源&#xff0c;能为威胁检测提供强力基础。在技术实现层面&#xff0c;戎码翼龙采用了先进的内核级数据采集技术&#xff0c;以超…

aardio - 关于字符串指针的操作

一、前言&#xff1a; aardio中的字符串&#xff0c;是不可修改的。 我们对字符串变量重新赋值一个不同的字符串&#xff0c;并不是“修改数据”&#xff0c;而是“更换地址”&#xff0c;实际上是赋予了一个新的内存指针。 先看下图&#xff0c;理解一下aardio中字符串变量…

跳动圆点加载动画

效果图: 完整代码: <!DOCTYPE html> <html> <head><meta charset="UTF-8" /><title>跳动圆点加载动画</title><style type="text/css">body {background: #ECF0F1;display: flex;justify-content: center;al…

MATLAB神经网络---激活层

reluLayer 修正线性单元 (ReLU) 层 ReLU 层对输入的每个元素执行阈值运算&#xff0c;其中任何小于零的值都设置为零。 此运算等效于 语法 layer reluLayer 创建一个 ReLU 层。 layer reluLayer(Name,Name) 创建一个 ReLU 层&#xff0c;并使用名称-值对组设置可选的 Nam…

【机器学习】机器学习与金融科技在智能投资中的融合应用与性能优化新探索

文章目录 引言机器学习与金融科技的基本概念机器学习概述监督学习无监督学习强化学习 金融科技概述股票预测风险管理资产配置 机器学习与金融科技的融合应用实时市场数据分析数据预处理特征工程 股票预测与优化模型训练模型评估 风险管理与优化深度学习应用 资产配置与优化强化…

产品管理:抓住关键要素的ABC分类法

目录 简介 ABC 分类法步骤 第一步&#xff1a;收集数据 第二步&#xff1a;处理数据 第三步&#xff1a;根据 ABC 分析表确定分类 第四步&#xff1a;绘制ABC分析图 第五步&#xff1a;根据 ABC 分析的结果&#xff0c;对 ABC 三类商品采取不同的管理策略 附&#xff1…

jenkins 自动化任务构建案例

一新建Item 输入一个名称&#xff0c;点击Freestyle project 进入到配置项 选择 This project is parameterized&#xff0c;点击String Parameter 添加 变量值 command添加执行的命令 二构建 点击build构建触发器 三查看控制台 控制台输出信息无误

双亲委派模型是什么,为什么要使用双亲委派模型

双亲委派模型是什么&#xff0c;为什么要使用双亲委派模型 在Java中&#xff0c;类加载器&#xff08;ClassLoader&#xff09;是负责将类文件加载到JVM中的关键组件。为了确保类加载过程的安全性和稳定性&#xff0c;Java引入了一种叫做双亲委派模型&#xff08;Parent Deleg…

联合数据库,申请出战!新指标“超级老人”揭示老年健康新视角,仅用logistic分析发文二区...

说到老年数据库&#xff0c;大家最熟悉的肯定是Charls&#xff0c;实际上类似免费好用的老年数据库还有很多&#xff0c;在没有思路的时候我们不妨看一下其他数据库的文章&#xff0c;说不定能找到新的思路或者切入点。 今天介绍的这篇文章就提出来一个新的概念-“超级老人”&a…

中国(广州)国际物流装备展圆满收官,铨顺宏邀您6月上海档案展

2024年5月29日-31日&#xff0c;为期三天的第十五届中国(广州)国际物流装备与技术展览会圆满收官。此次展会汇聚了物流装备与技术领域的众多行业精英和领先企业&#xff0c;展示了最新的技术和产品。铨顺宏科技作为物联网设备和技术服务领提供商&#xff0c;携RFID、BLE、UWB和…

按位拆分+前缀和,CF 1879D - Sum of XOR Functions

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1879D - Sum of XOR Functions 二、解题报告 1、思路分析 朴素暴力O(N^2)&#xff0c;考虑优化 由于要求的是异或值乘长度&#xff0c;那么我们可以按位考虑每一位异或值的贡献 我们枚举每一位 每次遍历…

TMCM-BB1是单轴板驱动器

TMCM-BB4 简介 TMCM-BB1和TMCM-BB4是Trinamic插槽式模块的基板。TMCM-BB1是单轴板&#xff0c;提供对一个MCU模块和一个驱动器模块的访问。TMCM-BB4是一个4轴板&#xff0c;提供对41模块插槽的访问。TMCM-0930模块采用单36针PCI插座&#xff0c;整个系统采用主MCU&#xff08;…

[Shell编程学习路线]--shell中重定向和管道符(详细介绍)

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f6e0;️Shell编程专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月12日10点50分 &#x1f004;️文章质量&#xff1a;93分 ——前言—— 在Shell编程中&#xff0c;重定向和管道符是两个…

超声波清洗机哪家好?四大人气爆单超声波清洗机汇总安利

在日常生活中&#xff0c;我们每天都在与灰尘和污渍作斗争&#xff0c;尤其是对于那些细小、精密的物品&#xff0c;如眼镜。眼镜不仅是视力矫正的工具&#xff0c;更是我们个人形象的一部分。一副干净、明亮的眼镜可以让我们的视线更加清晰。因为保持眼镜的清洁是一件很重要的…

接上篇---dbeaver如何导入csv文件(科学计数法)以及导出csv(科学计数法如何处理)

前提由于我用的是社区版本的&#xff0c;不支持excel&#xff0c;只支持csv导入导出 1.导入时候遇见科学计数法的解决方案&#xff1b; 由于我处理的是一些合同编码&#xff0c;虽然excel我给它设置成了文本类型&#xff0c;但是另存为csv的时候还是会变成科学计数法&#xf…

【关注】科大睿智祝贺企业通过ITSS公示名单

近日&#xff0c;根据信息技术服务标准符合性评估相关规定&#xff0c;现对以下单位进行公示&#xff0c;公示期5个工作日。公示期内如有异议&#xff0c;请提供持有异议的正式书面文件&#xff0c;包括持有异议的原因及证据、单位或个人真实名称及有效联系方式。小编祝贺多家服…

音视频封装的总接

1、封装涉及的基本概念 2、音视频封装基础3、封装总结 4、PS/TS码流封装层次图

c# 绘制正玄函数 控制台绘制

1.概要 2.代码 using System;class Program {static void Main(){const int width 80; // 控制台宽度 const int height 20; // 正弦波的高度范围 const double period 10.0; // 正弦波的周期 const double amplitude 5.0; // 正弦波的振幅 for (int x 0; x < wi…

衡量网络性能的指标

带宽 测速&#xff0c;下载速度一般是MB&#xff0c;运营商用的是b&#xff0c;之间有差别&#xff0c;100M带宽就是100M b 100个人访问同一个服务器&#xff0c;那么这个服务器的并发连接数就是100&#xff0c;有上限&#xff0c;受到性能的限制&#xff0c;当前面连接好多了…

JS :深拷贝解析与实现(附structuredClone语法测试)

浅拷贝简介 深拷贝是创建一个新对象&#xff0c;这个新对象包含原对象所有属性的全新拷贝&#xff0c;无论是基本数据类型还是引用类型的数据都会被完全复制一份&#xff0c;新旧对象间不存在任何关联&#xff0c;彼此独立。 前言 OK&#xff0c;最近又又又在学习JS的过程中…