Linux网络编程:Socket套接字编程(Server服务器 Client客户端)

文章目录:

一:定义和流程分析

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.mzph.cn/news/45088.shtml

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

相关文章

Git概述

目录 一、什么是Git 二、什么是版本控制系统 三、Git和SVN对比 SVN集中式 SVN优缺点 Git分布式 Git优缺点 四、Git工作流程 四个工作区域 工作流程 五、Git下载与安装 一、什么是Git 很多人都知道&#xff0c;林纳斯托瓦兹在1991年创建了开源的Linux&#xff0c;从…

不是说嵌入式是风口吗,那为什么工作还那么难找?

最近确实有很多媒体、机构渲染嵌入式可以拿高薪&#xff0c;这在行业内也是事实&#xff0c;但前提是你有足够的竞争力&#xff0c;真的懂嵌入式。 时至今日&#xff0c;能做嵌入式程序开发的人其实相当常见&#xff0c;尤其是随着树莓派、Arduino等开发板的普及&#xff0c;甚…

[NLP] BERT模型参数量

一 BERT_Base 110M参数拆解 BERT_base模型的110M的参数具体是如何组成的呢&#xff0c;我们一起来计算一下&#xff1a; 刚好也能更深入地了解一下Transformer Encoder模型的架构细节。 借助transformers模块查看一下模型的架构&#xff1a; import torch from transformers …

Linux 线程库中的接口介绍

1.pthread_create()创建线程 pthread_create()的语法形式&#xff1a; 参数解释&#xff1a; 第一个参数thread&#xff1a;事先创建好的pthread_t类型的参数。成功时thread指向的内存单元被设置为新创建线程的线程ID。 第二个参数attr&#xff1a;用于定制各种不同的线程属性…

SQL Monitor Crack,PostgreSQL监控的传入复制图表

SQL Monitor Crack,PostgreSQL监控的传入复制图表  现在&#xff0c;您可以在从Estate页面导出的Microsoft Excel报告的摘要标题中看到UTC偏移量。 添加了PostgreSQL监控的传入复制图表。 Microsoft PowerShell API现在支持将使用New-SqlMonitorWindowsHost和New-SqlMonitorin…

QT-播放原始PCM音频流

QT multimedia audioplay.h /************************************************************************* 接口描述&#xff1a;原始音频播放类 拟制&#xff1a; 接口版本&#xff1a;V1.0 时间&#xff1a;20220922 说明&#xff1a; ********************************…

【二叉树】450. 删除二叉搜索树中的节点

450. 删除二叉搜索树中的节点 解题思路 搭建框架如果当前节点只有一个子节点 那么直接返回该节点拥有两个子节点 循环找到右边的最小值节点 也就是不断找左孩子 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* …

RN 之 TODO

调研&#xff1a; 好处&#xff1a; 前端技术栈&#xff0c;代码容易迁移 跨ios&#xff0c;安卓端&#xff0c;一次编写同时部署 坏处&#xff1a; 难于工程init/构建 antd难于集成&#xff0c;db难于集成&#xff0c;缺乏树控件 可能有功能无法实现&#xff0c;例如x/…

pythond assert 0 <= colx < X12_MAX_COLS AssertionError

python使用xlrd读取excel时&#xff0c;报错&#xff1a; assert 0 < colx < X12_MAX_COLS AssertionError 大意是excel列太多了。主要是xlrd库的问题。最好的方法是不用它&#xff0c;但是我用的其他人提供的工具用到它&#xff0c;没法改。 尝试手动删除excel的列&am…

【AI大模型】训练Al大模型

大模型超越AI 前言 洁洁的个人主页 我就问你有没有发挥&#xff01; 知行合一&#xff0c;志存高远。 目前所指的大模型&#xff0c;是“大规模深度学习模型”的简称&#xff0c;指具有大量参数和复杂结构的机器学习模型&#xff0c;可以处理大规模的数据和复杂的问题&#x…

MybatisPlus整合p6spy组件SQL分析

目录 p6spy java为什么需要 如何使用 其他配置 p6spy p6spy是一个开源项目&#xff0c;通常使用它来跟踪数据库操作&#xff0c;查看程序运行过程中执行的sql语句。 p6spy将应用的数据源给劫持了&#xff0c;应用操作数据库其实在调用p6spy的数据源&#xff0c;p6spy劫持到…

Unity框架学习--音频管理器

using System.Collections; using System.Collections.Generic; using UnityEngine;/// <summary> /// 音频管理器 /// </summary> public class AudioManager : SingletonMonoAutoBase1_DonDestoryOnLoad<AudioManager> {//各个声道的AudioSource组件AudioS…

c#实现依赖注入

当谈到C#中的依赖注入(Dependency Injection,DI)时,我们可以使用一个简单的示例来说明它是如何工作的。依赖注入是一种设计模式,用于将依赖关系从一个类传递到另一个类,以实现松耦合和可测试性。 假设我们有一个简单的订单处理应用程序,其中包含两个主要类:OrderServi…

音视频 ffplay命令-主要选项

选项说明-x width强制显示宽带-y height强制显示高度-video_size size帧尺寸 设置显示帧存储(WxH格式)&#xff0c;仅适用于类似原始YUV等没有包含帧大小(WxH)的视频-pixel_format format格式设置像素格式-fs以全屏模式启动-an禁用音频&#xff08;不播放声音&#xff09;-vn禁…

leetcode第359场周赛

随机更新.... 7004. 判别首字母缩略词 给你一个字符串数组 words 和一个字符串 s &#xff0c;请你判断 s 是不是 words 的 首字母缩略词 。 如果可以按顺序串联 words 中每个字符串的第一个字符形成字符串 s &#xff0c;则认为 s 是 words 的首字母缩略词。例如&#xff0c…

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

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

go atomic原子操作详细解读

文章目录 概要1、基本知识1.1 原子操作是什么1.2 CPU怎么实现原子操作的&#xff1f; 2、atomic包2.1、 Add函数2.2、CompareAndSwap函数2.3、Swap函数2.4、Load函数2.5、Store函数 3、atomic.Value值 概要 atomic包是golang通过对底层系统支持的原子操作进行封装&#xff0c;…

华为将收取蜂窝物联网专利费,或将影响LPWAN市场发展

近日&#xff0c;华为正式公布了其4G和5G手机、Wi-Fi6设备和物联网产品的专利许可费率&#xff0c;其中包含了长距离通信技术蜂窝物联网。作为蜂窝物联网技术的先驱&#xff0c;华为是LTE Category NB (NB-IoT)、LTE Category M和其他4G物联网标准的主要贡献者。 在NB-IoT领域…

基于traccar快捷搭建gps轨迹应用

0. 环境 - win10 虚拟机ubuntu18 - i5 ubuntu22笔记本 - USB-GPS模块一台&#xff0c;比如华大北斗TAU1312-232板 - 双笔记本组网设备&#xff1a;路由器&#xff0c;使得win10笔记本ip&#xff1a;192.168.123.x&#xff0c;而i5笔记本IP是192.168.123.215。 - 安卓 手机 1.…

React2023电商项目实战 - 1.项目搭建

古人学问无遗力&#xff0c;少壮工夫老始成。 纸上得来终觉浅&#xff0c;绝知此事要躬行。 —— 陆游《《冬夜读书示子聿》》 系列文章目录 项目搭建App登录及网关App文章自媒体平台&#xff08;博主后台&#xff09;内容审核(自动) 文章目录 系列文章目录一、项目介绍1.页面…