【Linux网络编程】3.sockaddr地址结构、网络套接字函数

2024-05-07 10:28

本文主要是介绍【Linux网络编程】3.sockaddr地址结构、网络套接字函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

sockaddr地址结构

网络套接字函数

socket模型创建流程图

server(服务器端)

client(客户端)

socket

参数domain

参数type

参数protocol

返回值

bind

参数sockfd

参数addr

参数addrlen

返回值

listen

参数sockfd

参数backlog

返回值

accept

参数sockfd

参数addr

参数addrlen

返回值

connect

参数sockfd

参数addr

参数addrlen

返回值

测试代码1

测试结果

测试代码2

测试结果

测试代码3

测试结果

sockaddr地址结构

IP+port:在网络环境中唯一标识一个进程。  

man 7 ip
struct sockaddr {sa_family_t sa_family; 		/* address family, AF_xxx */char sa_data[14];			/* 14 bytes of protocol address */
};struct sockaddr_in {sa_family_t    sin_family;			/* Address family */  	//地址结构类型in_port_t      sin_port;			/* Port number */		//端口号struct in_addr sin_addr;			/* Internet address */	//IP地址
};struct in_addr {						/* Internet address. */uint32_t       s_addr;
};

用法:

struct sockaddr_in addr;
addr.sin_family = IP地址的类型;	//IPv4:AF_INET		IPv6:AF_INET6
addr.sin_port = htons(端口号);//s_addr的获取方式1
int dst;
inet_pton(IP地址的类型, "IP地址", (void *)&dst);
addr.sin_addr.s_addr = dst;//s_addr的获取方式2
addr.sin_addr.s_addr = htonl(INADDR_ANY);	//INADDR_ANY:取出系统中有效的任意IP地址,二进制类型。bind(fd, (struct sockaddr *)&addr, size);

网络套接字函数

socket模型创建流程图

server(服务器端)

  1. socket():创建socket。

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

  3. listen():设置监听上限。

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

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

  6. write(fd)

  7. close()

client(客户端)

  1. socket():创建socket。

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

  3. write():写数据到socket。

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

  5. 显示读取结果。

  6. close()。

socket

创建一个套接字。

man socket

参数domain

协议类型。

AF_INET:IPv4

AF_INET6:IPv6

AF_UNIX:本地套接字

参数type

数据传输协议。

SOCK_STREAM:流式协议,TCP传输

SOCK_DGRAM:UDP传输

参数protocol

0:默认值

返回值

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

失败:-1

bind

       给socket绑定一个地址结构(IP+port)。如果不使用bind绑定客户端地址结构, 采用“隐式绑定”。

man bind

参数sockfd

新套接字所对应的文件描述符,socket函数返回值。

参数addr

构造出IP地址加端口号,地址结构。

struct sockaddr_in addr;
addr.sin_family = IP地址的类型;	//IPv4:AF_INET		IPv6:AF_INET6
addr.sin_port = htons(端口号);//s_addr的获取方式1
int dst;
inet_pton(IP地址的类型, "IP地址", (void *)&dst);
addr.sin_addr.s_addr = dst;//s_addr的获取方式2
addr.sin_addr.s_addr = htonl(INADDR_ANY);	//INADDR_ANY:取出系统中有效的任意IP地址,二进制类型。bind(fd, (struct sockaddr *)&addr, size);

参数addrlen

地址结构的大小。

sizeof(addr)

返回值

成功:0

失败:-1

listen

设置同时与服务器建立连接的上限数。同时进行3次握手的客户端数量。

man listen

参数sockfd

新套接字所对应的文件描述符,socket函数返回值。

参数backlog

       上限数值。最大值128。数值越大,服务器丢客户端的概率就越小,连接速率也越快。上千万级数量的客户端同时请求连接单进程的服务器时,效果最明显。

返回值

成功:0

失败:-1

accept

阻塞等待客户端建立连接。

man 2 accept

参数sockfd

新套接字所对应的文件描述符,socket函数返回值。

参数addr

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

参数addrlen

传入传出参数,地址长度。

socklen_t clit_addr_len = sizeof(addr);&clit_addr_len

传入:addr的大小。

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

返回值

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

失败:-1。

connect

使用现有的socket与服务器建立连接。

man 2 connect

参数sockfd

新套接字所对应的文件描述符,socket函数返回值。

参数addr

传入参数。服务器的地址结构。

参数addrlen

服务器的地址结构的大小。

返回值

成功:0

失败:-1

测试代码1

服务器从客户端读取数据,然后将数据回送给客户端。

/*测试1服务器端代码,网络调试助手作客户端*/#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>int main(int argc, char *argv[])
{int flag;int fd_FWQ;                          //服务器文件描述符int fd_KFD;                          //客户端文件描述符char data[1024];                     //读取的数据int ZiJieShu;                        //字节数struct sockaddr_in DiZhi_JieGou_FWQ; //服务器地址结构struct sockaddr_in DiZhi_JieGou_KHD; //客户端地址结构socklen_t KeHuDuan_DaXiao;           //客户端大小char KHD_IP[1024];                   //客户端IPchar FWQ_IP[1024];                   //服务器IPfd_FWQ = socket(AF_INET, SOCK_STREAM, 0); //创建服务器套接字if (fd_FWQ == -1){perror("创建服务器套接字错误");exit(1);}DiZhi_JieGou_FWQ.sin_family = AF_INET;                //IPv4DiZhi_JieGou_FWQ.sin_port = htons(8080);              //端口号8080DiZhi_JieGou_FWQ.sin_addr.s_addr = htonl(INADDR_ANY); //获取系统中任意有效的IP地址flag = bind(fd_FWQ, (struct sockaddr *)&DiZhi_JieGou_FWQ, sizeof(DiZhi_JieGou_FWQ)); //绑定服务器的地址结构if (flag == -1){perror("绑定服务器地址结构错误");exit(1);}printf("服务器IP:%s,端口号:%d\n",inet_ntop(AF_INET, &DiZhi_JieGou_FWQ.sin_addr.s_addr, FWQ_IP, sizeof(FWQ_IP)),ntohs(DiZhi_JieGou_FWQ.sin_port));flag = listen(fd_FWQ, 128); //设置连接服务器上限数if (flag == -1){perror("设置连接上限数错误");exit(1);}KeHuDuan_DaXiao = sizeof(DiZhi_JieGou_KHD);fd_KFD = accept(fd_FWQ, (struct sockaddr *)&DiZhi_JieGou_KHD, &KeHuDuan_DaXiao); //阻塞监听客户端连接if (fd_KFD == -1){perror("阻塞监听客户端连接错误");exit(1);}printf("客户端IP:%s,端口号:%d\n",inet_ntop(AF_INET, &DiZhi_JieGou_KHD.sin_addr.s_addr, KHD_IP, sizeof(KHD_IP)), //网络转换成十进制本地IPntohs(DiZhi_JieGou_KHD.sin_port));                                             //网络转换成本地端口while (1){ZiJieShu = read(fd_KFD, data, sizeof(data));write(STDOUT_FILENO, data, ZiJieShu); //终端显示write(fd_KFD, data, ZiJieShu);}close(fd_KFD);close(fd_FWQ);return 0;
}

测试结果

服务器IP为0.0.0.0,表示所有地址、不确定地址、任意地址。

虚拟机端:

本机端:  

手机端:  

测试代码2

客户端与服务器的通讯。

/*测试2客户端代码,用网络调试助手作服务器*/#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>#define FWQ_IP "10.3.22.215" //服务器IPint main(int argc, char *argv[])
{int fd_FWQ; //服务器int flag;struct sockaddr_in FWQ_DiZhi; //服务器地址int ZiFuShu;                  //字符数char data[1024];              //数据fd_FWQ = socket(AF_INET, SOCK_STREAM, 0); //创建服务器套接字if (fd_FWQ == -1){perror("创建服务器套接字错误");exit(1);}FWQ_DiZhi.sin_family = AF_INET;                         //IPv4FWQ_DiZhi.sin_port = htons(10500);                       //端口号8080flag = inet_pton(AF_INET, FWQ_IP, &FWQ_DiZhi.sin_addr); //十进制IP转换网络IPif (flag == -1){perror("十进制IP转换网络IP错误");exit(1);}flag = connect(fd_FWQ, (struct sockaddr *)&FWQ_DiZhi, sizeof(FWQ_DiZhi));if (flag == -1){perror("连接服务器错误");exit(1);}printf("连接服务器完成。\n");while (1){ZiFuShu = read(fd_FWQ, &data, sizeof(data));write(fd_FWQ, "客户端接收到的数据是:", sizeof("客户端接收到的数据是:")); //将数据发回给服务器write(fd_FWQ, data, ZiFuShu);write(STDOUT_FILENO, "服务器发送的数据是:", sizeof("服务器发送的数据是:")); //显示接收到服务器的数据write(STDOUT_FILENO, data, ZiFuShu);sleep(1);}close(fd_FWQ);return 0;
}

测试结果

测试代码3

客户端与服务器实现数据传输。

/*测试3服务器端代码CeShi3_FWQ.c
*/#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>int main(int argc, char *argv[])
{int flag;int fd_FWQ;                          //服务器文件描述符int fd_KFD;                          //客户端文件描述符char data[1024];                     //读取的数据int ZiJieShu;                        //字节数struct sockaddr_in DiZhi_JieGou_FWQ; //服务器地址结构struct sockaddr_in DiZhi_JieGou_KHD; //客户端地址结构socklen_t KeHuDuan_DaXiao;           //客户端大小char KHD_IP[1024];                   //客户端IPchar FWQ_IP[1024];                   //服务器IPfd_FWQ = socket(AF_INET, SOCK_STREAM, 0); //创建服务器套接字if (fd_FWQ == -1){perror("创建服务器套接字错误");exit(1);}DiZhi_JieGou_FWQ.sin_family = AF_INET;                                               //IPv4DiZhi_JieGou_FWQ.sin_port = htons(8080);                                             //端口号8080DiZhi_JieGou_FWQ.sin_addr.s_addr = htonl(INADDR_ANY);                                //获取系统中任意有效的IP地址flag = bind(fd_FWQ, (struct sockaddr *)&DiZhi_JieGou_FWQ, sizeof(DiZhi_JieGou_FWQ)); //绑定服务器的地址结构if (flag == -1){perror("绑定服务器地址结构错误");exit(1);}printf("服务器IP:%s,端口号:%d\n",inet_ntop(AF_INET, &DiZhi_JieGou_FWQ.sin_addr.s_addr, FWQ_IP, sizeof(FWQ_IP)),ntohs(DiZhi_JieGou_FWQ.sin_port));flag = listen(fd_FWQ, 128); //设置连接服务器上限数if (flag == -1){perror("设置连接上限数错误");exit(1);}KeHuDuan_DaXiao = sizeof(DiZhi_JieGou_KHD);fd_KFD = accept(fd_FWQ, (struct sockaddr *)&DiZhi_JieGou_KHD, &KeHuDuan_DaXiao); //阻塞监听客户端连接if (fd_KFD == -1){perror("阻塞监听客户端连接错误");exit(1);}printf("客户端IP:%s,端口号:%d\n",inet_ntop(AF_INET, &DiZhi_JieGou_KHD.sin_addr.s_addr, KHD_IP, sizeof(KHD_IP)), //网络转换成十进制本地IPntohs(DiZhi_JieGou_KHD.sin_port));                                             //网络转换成本地端口while (1){ZiJieShu = read(fd_KFD, data, sizeof(data));if (ZiJieShu > 0){write(STDOUT_FILENO, "服务器接收到的数据为:", sizeof("服务器接收到的数据为:"));write(STDOUT_FILENO, data, ZiJieShu); //终端显示write(fd_KFD, "你好客户端,我是服务器,接收到的数据为:", sizeof("你好客户端,我是服务器,接收到的数据为:"));write(fd_KFD, data, ZiJieShu);}}close(fd_KFD);close(fd_FWQ);return 0;
}
/*测试3客户端代码CeShi3_KHD.c
*/#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>#define FWQ_IP "127.0.0.1" //服务器IPint main(int argc, char *argv[])
{int fd_FWQ; //服务器int flag;struct sockaddr_in FWQ_DiZhi; //服务器地址int ZiFuShu;                  //字符数char data[1024];              //数据fd_FWQ = socket(AF_INET, SOCK_STREAM, 0); //创建服务器套接字if (fd_FWQ == -1){perror("创建服务器套接字错误");exit(1);}FWQ_DiZhi.sin_family = AF_INET;                         //IPv4FWQ_DiZhi.sin_port = htons(8080);                       //端口号8080flag = inet_pton(AF_INET, FWQ_IP, &FWQ_DiZhi.sin_addr); //十进制IP转换网络IPif (flag == -1){perror("十进制IP转换网络IP错误");exit(1);}flag = connect(fd_FWQ, (struct sockaddr *)&FWQ_DiZhi, sizeof(FWQ_DiZhi));if (flag == -1){perror("连接服务器错误");exit(1);}printf("连接服务器完成。\n");while (1){write(fd_FWQ, "你好服务器,我是客户端,你好,世界!\n", sizeof("你好服务器,我是客户端,你好,世界!\n")); //将数据发给服务器printf("向服务器发送的数据是:你好服务器,我是客户端,你好,世界!\n");ZiFuShu = read(fd_FWQ, &data, sizeof(data));if (ZiFuShu > 0){write(STDOUT_FILENO, "服务器发送的数据是:", sizeof("服务器发送的数据是:")); //显示接收到服务器的数据write(STDOUT_FILENO, data, ZiFuShu);}sleep(1);}close(fd_FWQ);return 0;
}

测试结果

这篇关于【Linux网络编程】3.sockaddr地址结构、网络套接字函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/967094

相关文章

java中BigDecimal里面的subtract函数介绍及实现方法

《java中BigDecimal里面的subtract函数介绍及实现方法》在Java中实现减法操作需要根据数据类型选择不同方法,主要分为数值型减法和字符串减法两种场景,本文给大家介绍java中BigD... 目录Java中BigDecimal里面的subtract函数的意思?一、数值型减法(高精度计算)1.

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

Linux基础命令@grep、wc、管道符的使用详解

《Linux基础命令@grep、wc、管道符的使用详解》:本文主要介绍Linux基础命令@grep、wc、管道符的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录grep概念语法作用演示一演示二演示三,带选项 -nwc概念语法作用wc,不带选项-c,统计字节数-

Linux CPU飙升排查五步法解读

《LinuxCPU飙升排查五步法解读》:本文主要介绍LinuxCPU飙升排查五步法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录排查思路-五步法1. top命令定位应用进程pid2.php top-Hp[pid]定位应用进程对应的线程tid3. printf"%

Linux下安装Anaconda3全过程

《Linux下安装Anaconda3全过程》:本文主要介绍Linux下安装Anaconda3全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录简介环境下载安装一、找到下载好的文件名为Anaconda3-2018.12-linux-x86_64的安装包二、或者通

Linux系统之stress-ng测压工具的使用

《Linux系统之stress-ng测压工具的使用》:本文主要介绍Linux系统之stress-ng测压工具的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、理论1.stress工具简介与安装2.语法及参数3.具体安装二、实验1.运行8 cpu, 4 fo

Linux lvm实例之如何创建一个专用于MySQL数据存储的LVM卷组

《Linuxlvm实例之如何创建一个专用于MySQL数据存储的LVM卷组》:本文主要介绍使用Linux创建一个专用于MySQL数据存储的LVM卷组的实例,具有很好的参考价值,希望对大家有所帮助,... 目录在Centos 7上创建卷China编程组并配置mysql数据目录1. 检查现有磁盘2. 创建物理卷3. 创

Python函数返回多个值的多种方法小结

《Python函数返回多个值的多种方法小结》在Python中,函数通常用于封装一段代码,使其可以重复调用,有时,我们希望一个函数能够返回多个值,Python提供了几种不同的方法来实现这一点,需要的朋友... 目录一、使用元组(Tuple):二、使用列表(list)三、使用字典(Dictionary)四、 使

Linux查看系统盘和SSD盘的容量、型号及挂载信息的方法

《Linux查看系统盘和SSD盘的容量、型号及挂载信息的方法》在Linux系统中,管理磁盘设备和分区是日常运维工作的重要部分,而lsblk命令是一个强大的工具,它用于列出系统中的块设备(blockde... 目录1. 查看所有磁盘的物理信息方法 1:使用 lsblk(推荐)方法 2:使用 fdisk -l(