linux socket ip层配置,Linux下Socket通信(TCP实现)

近期在做的项目中,涉及到了进程间数据传输,系统的原本实现是通过管道,但是原有的实现中两个进程是在同一台机器,而且两个进程的关系为父子关系,而我们要做的是将其中一个进程移植到服务器上,因此两个进程要分开,所以管道必然是不可行的方案,而对于其它的进程通信方式,FIFO,消息队列,信号量和共享内存,显然也是不可行的。因此采取了通过socket的通信方式,即网络套接字,用来做数据的传输。接下来,将对自己对socket的学习一个整理,socket是什么?socket的创建,绑定,发送,接收消息过程进行分析,同时附带一个简单的代码实例。

网络套接字Socket

套接字是通信端点的抽象,其英文socket,即为插座,孔的意思。如果两个机子要通信,中间要通过一条线,这条线的两端要连接通信的双方,这条线在每一台机子上的接入点则为socket,即为插孔,所以在通信前,我们在通信的两端必须要建立好这个插孔,同时为了保证通信的正确,端和端之间的插孔必须要一一对应,这样两端便可以正确的进行通信了,而这个插孔对应到我们实际的操作系统中,就是socket文件,我们再创建它之后,就会得到一个操作系统返回的对于该文件的描述符,然后应用程序可以通过使用套接字描述符访问套接字,向其写入输入,读出数据。

站在更贴近系统的层级去看,两个机器间的通信方式,无非是要通过运输层的TCP/UDP,网络层IP,因此socket本质是编程接口(API),对TCP/UDP/IP的封装,TCP/UDP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。

Socket的创建

#include

int socket (int domain, int type, int protocol);

创建一个socket

int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

这样,我们便创建了一个socket,对于socket接收的参数都有什么意义呢?从上面,我们可以知道socket是对于底层网络通信的一个封装,而对于底层的网络通信也是具备多种类型的。而这些参数则是通过组合来表示各类通信的特征,从而建立正确的套接字。

domain:通信的特性,每个域有自己的地址表示格式,AF打头,表示地址族(Address family)

1460000010838132

type:套接字的类型,进一步确定通信特征。

1460000010838133

protocol:表示为给定域和套接字类型选择默认协议,当对同一域和套接字类型支持多个协议时,可以通过该字段来选择一个特定协议,通常默认为0.上面设置的socket类型,在执行的时候也会有默认的协议类型提供,比如SOCK_STREAM就TCP协议。

1460000010838134

从上面的socket类型中,我们看到有SOCK_RAW该种类型,SOCK_RAW套接字提供一个数据报接口。通过这个我们可以直接访问下面的网络层,绕过TCP/UDP,因此我们可以进行制定自己的传输层协议。

至此,我们的socket已经创建出来了,当我们不再使用的时候,我们可以调用close函数来将其关闭,释放该文件描述符,这样便可以得到重新的使用。

套接字通信是双向的,但是,我们可以采用shutdown函数来禁止一个套接字的I/O.

#include

int shutdown(int sockfd, int how);

how可以用来指定读端口或者是写端口,这样我们便可以关闭掉读端或者写端。

通信

我么已经创建好了Socket,接下来要做的就是通过socket进行通信了,在两个进程间进行通信,首先,我们要找到这些进程,找到进程,也就是能够有这些进程的唯一标示,有了这些标示,我们才可以确定通信的双方,然后进行数据的传输,对于一个通信进程的标示,所采取的方式是通过一个网络地址,也就是IP地址,战找到我们要通信的主机,然后通过端口号,找到相应的服务。网络地址+端口号唯一标示了一个我们要通信的目标进程。

字节序

字节序是处理器架构的特性,用来指示像整数这种数据类型的内部如何排序,大端和小端,因此如果通信双方的处理器架构不同,则会导致字节序的不一致的问题出现。最底层的网络协议指定了字节序,大端字节序,但是应用程序在处理数据时,则会遇到字节序不一致的问题。对此,系统提供了进行处理器字节序和网络字节序之间实施转换的函数。

#include

uint32_t htonl(uint32_t hostint32)//主机字节转化为网络字节序

uint16_t htons(uint16_t hostint16)

uint32_t ntohl(uint32_t netint32)//网络字节序转化为主机字节序

unint16_t ntohs(uint16_t netint16)

地址格式

上面,我们已经谈到如何表示一个要通信的进程,需要一个网络地址和端口,而在系统中如何具体的标示这一特征呢?根据之前socket的创建,我们知道不同socket对应了不同的通信特征,而对于不同的通信特征,其地址表示上也有一些差别。

这里我们只看一下IPV4因特网域地址的表示结构。

struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr;}

sin_family: 通信的的域,这里为AF_INET

sin_port:通信的端口

sin_addr:网络地址

套接字和地址关联

我们套接字已经创建好了,地址结构也已经了解了,接下来就是要将套接字和地址进行关联,关联的方法则是通过bind

函数。

#include

int bind(int sockfd, const struct sockaddr *addr, socklen_t len);

创建地址

struct sockaddr_in server_sockaddr;server_sockaddr.sin_family = AF_INET;server_sockaddr.sin_port = htons(PORT);server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

socklen_t server_len = sizeof(server_sockaddr);

bind(server_sockfd, (struct sockaddr*)&server_sockaddr, server_len)

通过bind函数,我们实现了socket和地址的绑定。

建立连接

socket建立好了,地址也绑定好了,这个时候,我们就可以进行连接了,要有一方进行连接的建立,通过调用connect

函数。

#include int connect(int sockfd, const struct sockaddr *addr, socklen_t len);

sockfd:这个就是本地端socket描述符,如果我们没有赋值,系统会默认提供一个值。只有当服务器开启,并正常运行,我们的连接才能够正常建立。

如何让socket接收连接请求呢?在另一端,我们调用listen

方法来接收连接请求。

#include int listen(int sockfd, int backlog);

sockfd:绑定了地址的socket文件描述符。

backlog:服务器负载,提示系统进程所要入队的未完成请求数量。

通过listen我们得到了连接请求,接下来,就是建立连接,通过函数accept

#include

int accept(int sockfd, struct sockaddr *restric addr, socklen_t *restrict len);

调用accept函数的返回值是套接字文件描述符,该描述符连接到调用connect的客户端。

一旦服务器调用了listen,所用的套接字就能接收连接请求,使用accept函数获得连接请求并建立连接。

使用accept函数获得连接请求并建立连接。

int accept(int sockfd, struct sockaddr *restrict addr, socklent_t *restrict len);

当调用accept函数会产生一个新的套接字,这个新的套接字和原始套接字有相同的套接类型。这个时候,我们可以传入一个指向socket的指针和其大小,设置之后,调用了accept就会将客户端的地址进行缓冲。

数据传输

连接已经建立好了,由于socket本身都是文件描述符,因此接下来就可以调用所read和write来通过套接字通信。

对于面向连接的数据传输,我们需要的两个函数是send和recv。

#include

ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags)

sockfd:accept返回的socket文件描述符。

buf:发送数据,

bytes:发送数据大小

flags:对于传送数据的一些配置项

对于不同的socket类型,系统提供了不同的发送方法。

#include

ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags)

具体参数和send类似。

socket选项设置

对于Socket,系统提供了更具体细致化的一些配置选项,通过这些配置选项,我们可以进行进一步具体的配置。

#include

int setsockopt(int sockfd, int level, int option, const void *val, socklen_t len);

1460000010838135

sockfd:我们要进行配置的socket

level:根据我们选用的协议,配置相应的协议编号

option:选项即为上表

最后参数是用来存放返回值

实现demo实例

server

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PORT 22468

#define KEY 123

#define SIZE 1024

int main()

{

char buf[100];

memset(buf,0,100);

int server_sockfd,client_sockfd;

socklen_t server_len,client_len;

struct sockaddr_in server_sockaddr,client_sockaddr;

/*create a socket.type is AF_INET,sock_stream*/

server_sockfd = socket(AF_INET,SOCK_STREAM,0);

server_sockaddr.sin_family = AF_INET;

server_sockaddr.sin_port = htons(PORT);

server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

server_len = sizeof(server_sockaddr);

int on;

setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR,&on,sizeof(on));

/*bind a socket or rename a sockt*/

if(bind(server_sockfd, (struct sockaddr*)&server_sockaddr, server_len)==-1){

printf("bind error");

exit(1);

}

if(listen(server_sockfd, 5)==-1){

printf("listen error");

exit(1);

}

client_len = sizeof(client_sockaddr);

pid_t ppid,pid;

while(1) {

if((client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_sockaddr, &client_len)) == -1){

printf("connect error");

exit(1);

} else {

printf("create connection successfully\n");

int error = send(client_sockfd, "You have conected the server", strlen("You have conected the server"), 0);

printf("%d\n", error);

}

}

return 0;

}

client

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SERVER_PORT 22468

#define MAXDATASIZE 100

#define SERVER_IP "Your IP"

int main() {

int sockfd, numbytes;

char buf[MAXDATASIZE];

struct sockaddr_in server_addr;

printf("\n======================client initialization======================\n");

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror("socket");

exit(1);

}

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(SERVER_PORT);

server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

bzero(&(server_addr.sin_zero),sizeof(server_addr.sin_zero));

if (connect(sockfd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr_in)) == -1){

perror("connect error");

exit(1);

}

while(1) {

bzero(buf,MAXDATASIZE);

printf("\nBegin receive...\n");

if ((numbytes = recv(sockfd, buf, MAXDATASIZE, 0)) == -1){

perror("recv");

exit(1);

} else if (numbytes > 0) {

int len, bytes_sent;

buf[numbytes] = '\0';

printf("Received: %s\n",buf);

printf("Send:");

char msg[100];

scanf("%s",msg);

len = strlen(msg);

//sent to the server

if(send(sockfd, msg,len,0) == -1){

perror("send error");

}

} else {

printf("soket end!\n");

break;

}

}

close(sockfd);

return 0;

}

总结

最近也在看的一个RPC框架,thrift,定义好我们的接口文件,然后可以帮助我们生成两端的桩文件,而且实现原理上,也不过是通过底层的socket通信做了包装,执行相应的调用。socket通信在大三的OS课上写过,本文主要目的记录本次学习,对于socket知识进行了一个回顾。

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

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

相关文章

【EOJ Monthly 2019.02 - D】进制转换(思维,取模,高精度大数)

题干: 单测试点时限: 2.0 秒 内存限制: 256 MB “他觉得一个人奋斗更轻松自在。跟没有干劲的人在一起厮混,只会徒增压力。” QQ 小方决定一个人研究研究进制转换。 很快,QQ 小方就遇到问题了。他现在想知道在十进制范围 [l,r] 内有多少整…

linux i2c触摸屏驱动程序,触摸屏i2c设备和驱动的创建流程及方法

添加i2c设备的流程:1. 初始化 i2c_board_info 结构信息 和 i2c_driver 结构//设备驱动结构体static struct i2c_driver goodix_ts_driver {.probe goodix_ts_probe,.remove goodix_ts_remove,#ifndef CONFIG_HAS_EARLYSUSPEND.suspend goodix_ts_su…

【EOJ Monthly 2019.02 - E】中位数(二分 ,中位数 ,−1/1变换,dp求解DAG最长路)

题干: E. 中位数 单测试点时限: 10.0 秒 内存限制: 256 MB “你的地图是一张白纸,所以即使想决定目的地,也不知道路在哪里。” QQ 小方最近在自学图论。他突然想出了一个有趣的问题: 一张由 n 个点,m 条边构成的…

linux桌面变成黑白,用虚拟机装了linux后开启为什么界面是黑色的呢?

20寸显示器的标准分辨率是1680*1050进入到/boot/grub/目录下,然后就可以看到里面有个名为menu.lst的文件,用vim将其打开,可以看到以下内容:# grub.conf generated by anaconda## Note that you do not have to rerun grub after m…

【EOJ Monthly 2019.01 - E】唐纳德先生与假骰子(假概率问题)

题干: 单测试点时限: 6.0 秒 内存限制: 1024 MB 嗨,唐纳德先生又来了。 他又带了一枚假骰子,这个骰子的各个面的点数依然是 1,2,3,4,5,6 ,但是六个面向上的概率却不一定都是 1/6 ,而变成了 p1,p2,p3,p4,p5,p6 。 …

linux 编译安装picocom,Linux pico命令

Linux pico命令Linux pico命令用于编辑文字文件。pico是个简单易用、以显示导向为主的文字编辑程序,它伴随着处理电子邮件和新闻组的程序pine而来。语法pico [-bdefghjkmqtvwxz][-n][-o][-r][-s][][文件]参数说明:-b 开启置换的功能。-d 开启删除的功能。…

【Hihocoder - offer编程练习赛93 套题题解】交错01串(贪心,暴力)方格矩阵高度(模拟)数对(STLmultiset)修整土地(网络流)

A: 题干: 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi要将一个01串S传输给小Ho,由于S非常长,所以小Hi决定用长度为N的2个数组A [A1, A2, ..., AN]和B [B1, B2, ..., BN]表示S。 具体来讲,是…

linux防火墙配置连接atlas,ATLAS在ubuntu下的安装使用

1, 根据atlas的安装文档, 首先要switch off cpu throttling.在Ubuntu系统上要首先安装cpufrequtils和cpufreqd这两个包, 也许还要安装powernowd包,然后执行sudo /usr/bin/cpufreq-selector –g. 不过幸运的是, 我在server上安装的时候发现cputhrottling已经disable了(否则在con…

【CodeForces - 545 ABCDE套题训练题解】贪心, 构造,模拟,dp,最短路树(Dijkstra+变形)

A: 题干: Input The first line contains integer n (1 ≤ n ≤ 100) — the number of cars. Each of the next n lines contains n space-separated integers that determine matrix A. It is guaranteed that on the main diagonal there ar…

linux搜索pdf文件,桌面应用|如何使用 pdfgrep 从终端搜索 PDF 文件

诸如 grep 和 ack-grep 之类的命令行工具对于搜索匹配指定正则表达式的纯文本非常有用。但是你有没有试过使用这些工具在 PDF 中搜索?不要这么做!由于这些工具无法读取PDF文件,因此你不会得到任何结果。它们只能读取纯文本文件。顾名思义&…

【CodeForces - 546C 】Soldier and Cards (模拟)

题干: Two bored soldiers are playing card war. Their card deck consists of exactly n cards, numbered from 1 to n, all values are different. They divide cards between them in some manner, its possible that they have different number of cards. Th…

linux wifi 蓝牙冲突,linux 下 无线 wifi 蓝牙 无法启用

linux 下 无线 wifi 蓝牙 无法启用装了Debian squeeze 后发现无线不能打开首先想到的是装驱动于是在wiki.debian.org上查了下以重新装了下驱动#aptitude install firmware-b43-installler#modprobe b43# iwconfiglo no wireless extensions.eth0 no wireless exten…

Linux中wait接口用于延时,linux2.6驱动编写参考

1、 使用新的入口必须包含 module_init(your_init_func);module_exit(your_exit_func);老版本:int init_module(void);void cleanup_module(voi);2.4中两种都可以用,对如后面的入口函数不必要显示包含任何头文件。2、 GPLMODULE_LICENSE("Dual BSD/…

【51nod - 1108】距离之和最小 V2(曼哈顿距离,中位数性质)

题干&#xff1a; 三维空间上有N个点, 求一个点使它到这N个点的曼哈顿距离之和最小&#xff0c;输出这个最小的距离之和。 点(x1,y1,z1)到(x2,y2,z2)的曼哈顿距离就是|x1-x2| |y1-y2| |z1-z2|。即3维坐标差的绝对值之和。 收起 输入 第1行&#xff1a;点的数量N。(2 <…

Linux实验室阿里云证书,开发者云体验实验室

{"data":[{"title":"技术领域","data":[{"title":"全部","key":1,"children":[{"title":"程序语言","key":12,"children":[{"title":&qu…

【OpenJudge - noi - 7624】山区建小学(dp)

题干&#xff1a; 总时间限制: 1000ms 内存限制: 65536kB 描述 政府在某山区修建了一条道路&#xff0c;恰好穿越总共m个村庄的每个村庄一次&#xff0c;没有回路或交叉&#xff0c;任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为di&#xff08;为…

nuc8i7beh安装linux随机重启,【图片】来分享一下我的NUC8I7BEH【intelnuc吧】_百度贴吧...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼测试来了&#xff0c;Linux 脚本&#xff0c;2G测试&#xff0c;操完这次以后休息俩礼拜。ssd随机读4kfio -filename./ran4K.log -direct1 -iodepth 1 -thread -rwrandread -ioenginepsync -bs4k -size2G -numjobs10 -runtime1000 …

【Codeforces - 找不到题号】三元环计数(bitset优化,压位)

题干&#xff1a; 给你一个二维字符矩阵&#xff0c;如果 ( i , j ) 为 表明 两点之间有一条有向边&#xff0c;为-表示没有边&#xff0c;那么你要找出所有的三元环的个数。顶点数N<1500。 解题报告&#xff1a; 考虑最暴力的方法&#xff0c;开个二维数组来存每两个顶点之…

自定义函数删除字母C语言,[编程入门]自定义函数之字符提取-题解(C语言代码)...

解题思路:输入一个字符串&#xff0c;调用函数&#xff0c;遍历字符串中每一个字符&#xff0c;看是否含有aeiou字符&#xff0c;若有&#xff0c;将其保存到另一个字符型数组中&#xff0c;在主函数中对得到的字符型数组进行排序&#xff0c;输出。注意事项:题目要求顺序输出元…

【Hihocoder - offer编程练习赛39 - D】前缀后缀查询(后缀字典树,哈希,思维)

题干&#xff1a; 时间限制:10000ms 单点时限:1000ms 内存限制:512MB 描述 给定一个包含N个单词的字典:{W1, W2, W3, ... WN}&#xff0c;其中第i个单词Wi有具有一个权值Vi。 现在小Hi要进行M次查询&#xff0c;每次查询包含一个前缀字符串Pi和一个后缀字符串Si。他希望…