Linux系统编程阶段知识点总结(二)

六、信号与管道

七、IPC通讯

八、多线程

这三章内容已单独发布过;

 

九、网络编程

1.局域网和广域网

局域网:在某一个小的范围内的主机组成的网络。一个路由器下挂载的设备组成的网络,是一个局域网。

广域网:就是把无数个局域网连接在一起,组成的就是广域网。

信号、管道、消息队列、共享内存、信号量都是在主机范围内的进程间的通讯。而网络存在的意义跨主机的进程间进行数据的交互。

2:如何链接百度服务器

DNS:域名解析

        1)输入www.baidu.com;

        2)访问DNS服务器;

        3)DNS服务器将域名解析成IP;

        4)通过拿到的ip访问百度服务器,真正能访问到百度服务器的,是ip地址。

3:IP地址的分类

IP地址:IPV4的地址,4个字节(0.0.0.0-255.255.255.255),IPV4最多能分配42亿左右的ip地址,IPV4是远远不够使用的。

引入IPV6,128Bit,16字节,ipv6还没有铺开。

IPV4,4字节,32bit,ip地址用点分十进制来表示,IP地址 = 网络号+主机号。IP地址根据网络号和主机号来分,分为A、B、C三类及特殊地址D、E。全0和全1的都保留不用。

 

A类:

地址范围:1.0.0.0-127.255.255.255

(00000001.00000000.00000000.00000000~01111110.111111111.11111111.11111110)(这种写法是把全0全1都算进去了,其它几类类似)

网络号范围: 1~127 (0000 0001 ~ 0111 1111)

默认子网掩码:255.0.0.0 或 0xFF000000(十六进制)

前1个字节(8位)为网络号,后3个字节(24位)为主机号。

A类第1位必须是0。A类地址一般是超大型的企业会使用。

B类:

地址范围:128.1.0.1-191.255.255.255

网络号范围:128.1 ~ 191.255 (可用范围)

默认子网掩码:255.255.0.0 或 0xFFFF0000(十六进制)

前2个字节(16位)为网络号,后2个字节(16位)为主机号。

前两位固定为10。

最大网络数:2^14-1

最大主机数:2^16-2

一般用于中等规模网络。

C类:

地址范围:192.0.1.1-223.255.255.254

网络号段范围:192.0.1 ~ 223.255.255

子网掩码:255.255.255.0 或 0xFFFFFF00 (十六进制)

前3个字节(24位)为网络号,后1个字节(8位)为主机号。

前3位固定为110。

最大网络数:2^21-1

最大主机数:2^8-2

一般用于小型网络。

D类:

地址范围:224.0.0.1-239.255.255.254

是多播地址。该类IP地址的最前面为“1110”,所以地址的网络号取值于224~239之间。一般用于多路广播用户。

E类:

是保留地址。该类IP地址的最前面为“1111”,所以地址 的网络号取值于240~255之间。

4:端口号的概念

区分一台主机接收到的数据包应该转交给哪个进程来处理。 端口号为16位的无符号整形数,范围0-65535,1-1023 系统占用,1024-49150,是我们可用的端口。

访问一个服务器的时候,假如走的是http或者是https协议

http:常见的端口   80 、8080

https:常见的端口  443 、8443

5:网络字节序

编程界有两种数据的存储的方式

大端存储:高字节存放在低地址,低字节存放在高地址

小端存储:高字节存放在高地址,低字节存放在低地址

电脑:用的是小端模式

网络里:大端模式

6:TCP和UDP通讯(重点)

TCP:

        在通讯之前必须要建立一个网络链接;

        提供一个可靠的文件传输;

        效率略低;

UDP:

        在通讯之前不需要建立网络链接;

        提供的是不可靠的文件传输;

        效率略高;

TCP和UDP的区别:

tcp提供面向链接的可靠文件传输;

udp提供面向非链接的不可靠文件传输。

  TCP三次握手

        1)客户端先发送syn包到服务器;

        2)服务端发送ack包和自己的syn包;

        3)向服务器发送确认包 ack包。

7:ip地址的网络字节序的转换

inet_addr():将小端模式的ip(点分十进制的ip)地址转换成大端模式(32位2进制)

头文件:

        #include <sys/socket.h>

        #include <netinet/in.h>

        #include <arpa/inet.h>

原型:in_addr_t inet_addr(const char *cp);

参数:const char *cp:要转换的ip地址,"192.168.1.1"

其它转换函数:

        int inet_aton(const char *cp, struct in_addr *inp);

        //点分十进制IP-->网络字节的32位二进制数值

        char *inet_ntoa(struct in_addr in);//32-->点分十进制

        int inet_pton(int af, const char *src, void *dst);

        //类比inet_aton  192.168.10.1 -> 11000000 10101000 00001010 00000001

        const char *inet_ntop(int af, const void *src,char *dst, socklen_t cnt);

        //11000000 10101000 00001010 00000001 > 192.168.10.1

        af:AF_INET:表示为ipv4

        AF_INET6:表示为ipv6

8:套接字的概念

linux下文件的分类(linux下一切皆文件)

普通文件   -

目录文件   d

链接文件   l

管道文件   p

字符设备文件  c

块设备文件   b

套接字文件   s

套接字:他是一个特殊的文件,文件就能读、能写。普通的文件创建的时候,open即可。套接字文件,创建的时候需要借助socket函数。

作用:

        1)能够绑定ip;

        2)绑定端口;

        3)监听整个网络的信息;

        4)设置网络的属性;

        5)可以被别人链接;

        6)可以链接别人。

9:套接字的创建

socket():创建一个套接字

头文件:

        #include <sys/types.h>        

        #include <sys/socket.h>

原型:int socket(int domain, int type, int protocol);

参数:

        int domain:IP的类型,IPV4  IPV6

        AF_INET:表示为ipv4

        AF_INET6:表示为ipv6

        int type:IP协议的类型,TCP 和UDP

                SOCK_STREAM:TCP协议  流式套接字

                SOCK_DGRAM:UDP协议  数据报

        int protocol:固定填 0

返回值:

        返回的就是套接字的文件的描述符(整型数);

        文件描述符跟文件操作里(非缓冲区文件操作)文件描述符起始位置是一样的,套接字也是从3开始的,0 1 2默认的被分配为:标准输入、标准输出、标准错误

10:如何链接服务器

connect():连接服务器

头文件:

        #include <sys/types.h>         

        #include <sys/socket.h>

原型:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数:

        nt sockfd:创建的套接字

        const struct sockaddr *addr:服务端信息的结构体

结构体里包含了{

ip的类型;

ip地址;

服务器的端口};

socklen_t addrlen :服务端信息结构体的大小

返回值:成功返回  0    失败返回 非零

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++

服务端信息的结构体:

struct sockaddr //此结构体不常用

{

unsigned short int sa_family; //调用 socket()时的 domain 参数,即 AF_INET 值。

char sa_data[14];    //最多使用 14 个字符长度

};

struct sockaddr_in //常用的结构体

{

unsigned short int sin_family;   //AF_INET

uint16_t sin_port;           //为使用的 port 编号

struct in_addr sin_addr;      //为 IP 地址

unsigned char sin_zero[8];   //未使用

};

struct in_addr

{

uint32_t s_addr; // =inet_addr("192.168.1.22")

};

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

因为connect()函数里面调用的是第一个结构体,所以需要把第二类强转为第一类。

struct sockaddr_in seraddr;  //给第二类结构体赋初值

seraddr.sin_family=AF_INET;

seraddr.sin_port=htons(9999);

seraddr.sin_addr.s_addr=inet_addr("192.168.15.1");

connect(sfd, (struct sockaddr *)&seraddr, sizeof(struct sockaddr));//强转

11:Tcp服务端(客户端实现函数)

                ​​​​​​​        ​​​​​​​        

                                                                 TCP协议编程框架

++++++++++++++++++++++++++++++++++++++++++++++++++++++

socket():创建一个套接字

头文件:

        #include <sys/types.h>          

        #include <sys/socket.h>

原型:int socket(int domain, int type, int protocol);

参数:

        int domain:IP协议

        AF_INET:ipv4

        AF_INET6:ipv6

        int type:IP协议的类型

        SOCK_STREAM:  tcp  流式套接字

        SOCK_DGRAM:  udp  数据报

int protocol:固定填0

返回值:成功创建的套接字

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

bind():绑定服务器的属性(端口,ip),绑定ip 绑定自己的ip即可。

头文件:

        #include <sys/types.h>          

        #include <sys/socket.h>

原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

参数:

        int sockfd:套接字

        const struct sockaddr *addr:服务器的信息的结构体

        socklen_t addrlen:结构体的大小

返回值:成功返回0  失败返回-1

struct sockaddr {

               sa_family_t sa_family; //ipv4或者ipv6

               char  sa_data[14];   //包含ip端口

                 }:

  struct sockaddr_in {

               sa_family_t  sin_family;  //ipv4还是ipv6

               in_port_t    sin_port;   //端口号

               struct in_addr sin_addr;  //存放ip的结构体

                   };

struct in_addr {

               uint32_t   s_addr;    //ip地址

               };

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

listen():监听整个网络

头文件:

        #include <sys/types.h>         

        #include <sys/socket.h>

原型:int listen(int sockfd, int backlog);

参数:

        int sockfd:套接字

        int backlog:能接受的最大的链接数  最大128

返回值:成功返回0  失败返回-1

++++++++++++++++++++++++++++++++++++++++++++++++++++++

accept():接收客户端的链接

头文件:

        #include <sys/types.h>         

        #include <sys/socket.h>

原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数:

        int sockfd:套接字

        struct sockaddr *addr:客户端的ip,端口信息存放的结构体

        socklen_t *addrlen:用来存放客户端结构体长度的指针

返回值:服务器用来跟客户端进行通讯的新的套接字。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

recv():接收发来的消息

头文件:

        #include <sys/types.h>         

        #include <sys/socket.h>

原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);

参数:

        int sockfd:新的套接字

        void *buf:读取到内容存放的位置

        size_t len:读取的长度

        int flags  :0,读不到就阻塞

返回值:成功返回 读取到的字节数

          失败返回  -1

          返回 0  表示客户端下线

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

send():发送一条消息

头文件:

        #include <sys/types.h>         

        #include <sys/socket.h>

原型:ssize_t send(int sockfd, const void *buf, size_t len, int flags);

参数:

        int sockfd:新的套接字

        const void *buf:要发送的内容

        size_t len:长度

        int flags:0

返回值:成功返回  成功发送的字节数  失败返回   -1

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

connect():客户端对服务器发起链接

头文件:

        #include <sys/types.h>         

        #include <sys/socket.h>

原型:int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

参数:

        int sockfd:创建的套接字

        const struct sockaddr *addr:服务器的ip、端口

        socklen_t addrlen:结构体的大小

返回值:成功返回  0   失败返回  -1

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

12.udp通讯

1)udp通讯的特点

速度快、不可靠、udp可以进行组播和广播

2)udp服务端模型:

        (1)创建套接字

        (2)绑定服务端相关的信息

        (3)接受客户端发来的消息

        (4)发送消息给客户端

udp客户端模型:

        (1)创建套接字

        (2)向服务端发送消息

        (3)接收服务端的消息

3)udp相关的函数

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

recvfrom():接收udp的消息

函数的头文件

        #include <sys/types.h>

     #include <sys/socket.h>

函数的原型

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

函数的参数

        int sockfd:udp的套接字

        void *buf:接受到的消息存放的位置

        size_t len:接受的长度,

取值,len=(socklen_t)sizeof(struct sockaddr);

int flags:0 ,表示读不到就阻塞

struct sockaddr *src_addr:如果服务端用,就是客户端的ip,端口的相关的信息结构体

socklen_t *addrlen:客户端信息的结构体的大小

函数的返回值

        成功返回读取到的字节数

        失败返回  -1

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

函数功能:发送一条udp消息

函数的头文件

        #include <sys/types.h>

    #include <sys/socket.h>

函数的原型

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

函数的参数

        int sockfd:套接字

        const void *buf:要发送的内容

        size_t len:发送内容的长度

        int flags:0,发不出则阻塞

const struct sockaddr *dest_addr:发送的对象的ip,端口信息结构体

socklen_t addrlen:结构体的大小

函数的返回值

        成功返回 成功发送的字节数

        失败返回   -1

+++++++++++++++++++++++++++++++++++++++++++++++++++++++

13.udp的组播

组播:

        假如一个人创建了一个组播;

        另外一个进程只要加入了这个组播;

        创建者往组播里发东西; 

        加入组播的所有的人都能收到创建者发的消息

udp默认的不打开组播和广播,要想打开组播和广播功能,需要借助一个函数setsockopt();还需要有一个组播的地址,(224.0.0.0-239.255.255.255).

函数的功能:设置套接字的属性

函数的头文件:

        #include <sys/types.h>         

   #include <sys/socket.h>

函数的原型:

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

函数的参数:

        int sockfd:套接字

        int level所设置的网络层

        IPPROTO_IP:IP层 用于设置广播以及组播

        SOL_SOCKET:用于快速的释放底层ip

        int optname:

        属于ip层的有两个宏定义

        IP_MULTICAST_IF:创建一个多播组

        IP_ADD_MEMBERSHIP:加入一个多播组

        属于SOL_SOCKET:

        SO_BROADCAST:开启套接字的广播

        SO_REUSEADDR:快速的释放底层ip

const void *optval:根据前边的选项不同,这个参数也是不同的

加入是要加入一个多播组,就需要如下结构体:

struct ip_mreqn {

               struct in_addr imr_multiaddr; //要加入的多播组的ip

               struct in_addr imr_address;  //自己的ip                                

               int imr_ifindex;            //物理网卡的索引号

//if_name_toindex("ens33")

                  };

socklen_t optlen:表示前边一个参数的长度

函数的返回值:成功返回  0   失败返回  -1

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

十、多路io复用

1.多路io复用的作用及意义

说明:

tcp服务端,共涉及两类的套接字。第一类:它自己的套接字这个套接字是专门用来处理新的客户端的链接的,绑定服务器的ip和端口;第二类:在有客户端连接我的tcp服务器之后,服务端通过调用accept()函数接收客户端发起的链接后,会产生一个新的套接字,这个套接字就是用来跟客户端收发消息的。当有很多个客户端同时来连服务端的时候:不借助多线程,当有一个客户端连上我之后,假如客户端不发消息,服务端就一直阻塞在接收消息那。借助多线程,当我的客户端有很多个的时候(有128个),就需要起129线程,管理起来就会很不方便,多线程有一个比较致命的缺陷:一死俱死,容易造成服务器的不稳定。

多路io复用作用:用来解决服务器的多并发的。

2.套接字文件阻塞的问题

服务器多并发存在的问题,本质上是我的套接字文件阻塞的问题,

第一个阻塞的点:accept():

当没有客户端连服务器的时候,会阻塞,当有客户端来连接我的时候,会解除阻塞,相当于套接字(服务器本身的套接字)文件产生了异动(可读性),解除阻塞;

第二阻塞的点,recv():  

当客户端没有给服务端发消息的时候会陷入阻塞,当客户端发了消息,会解除阻塞,相当于套接字(用来跟客户端通讯的套接字)产生了异动 ,可读性。

多路io复用(一种机制):当有客户端要来链接服务器的时候再去调用accept(),当有客户端给服务器发消息的时候再去调用recv(),这样的话服务端的进程就不会阻塞了。

多路io重点掌握两类:select和poll轮询

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

3.select的机制

select他的最主要的功能就是监测文件,监测文件的异动。

select的机制工作步骤:

1)会创建一个表,这个表最大能有1024个格;

2)当服务器起来之后,就有了自己的第一个套接字,这个就是我的第一类的套接字文件,将这个套接字放到select表里,select就会监测我的这个套接字的异动,select函数则会进入阻塞;

3)假如有客户来链接我的服务器的时候,select表就会产生异动,就会解除select的阻塞,服务端就可以去调用accept函数来接受客户端的链接,会产生一个新的套接字;

4)我们需要将新产生的这个套接字放入select这张表里;

5)再调用select函数的时候,我们就会监测两个套接字 ,一个一类,一个二类的,对应的就是服务端本身的套接字和用来跟客户端通讯的套接字。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

重点函数:

函数功能:多路io复用

函数的头文件

        #include <sys/time.h>

        #include <sys/types.h>

        #include <unistd.h>

函数的原型

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

函数的参数

        int nfds:表格里的最大的文件描述符+1

        fd_set *readfds:监测文件可读性的表格,一般只用这个

        fd_set *writefds:监测文件的可写性的表格,一般并不,NULL

        fd_set *exceptfds:监测文件异常的表格,一般不用,填写NULL

struct timeval *timeout:监测表格的最大的时间,在规定的时间里去监测表格里的所有文件,在这个规定的时间内产生了异动,则返回正常值;在这个规定的时间内没有产生异动则返回出错(超时),一般也是填写NULL,表示无限期的等待。

函数的返回值:超时返回,0    失败返回 -1

有事件发生,则返回事件的个数

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

表格操作系统提供了一些宏

void FD_CLR(int fd, fd_set *set);从表格里删除一个文件描述符

int FD_ISSET(int fd, fd_set *set);检查文件描述符是否在这个表格中

void FD_SET(int fd, fd_set *set);添加一个文件描述符到表格里

void FD_ZERO(fd_set *set);清空一个表格++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

在使用select表格的时候,需要注意的点:

假如我的表格里有很多个文件描述符,当我的表格里的文件描述符有产生异动的时候,会将没有产生异动的文件描述符全部清除掉,所以需要多创建一个select表格做备份。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

4.poll轮询的特点:

poll轮询思路跟select大致是一样的,也是监测文件的异动,包括文件的可读、可写、出错。

缺点:相对于select来说,poll比较不灵活,效率也没有select高;添加新的文件到监测的表里比select要难;反应没有select快。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

poll轮询函数

函数功能:多路io复用

函数的头文件:#include <poll.h>

函数的原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);

函数的参数

struct pollfd *fds, 结构体

struct pollfd {

               int fd;         //要监测的文件描述符

               short events;   //请求事件(监测的事件)

                        POLLIN:监测文件是否产生可读性

                        POLLOUT:监测文件是否产生可写性

                        POLLERR:监测文件是否发生异常

               short revents;  //返回事件            

 };

nfds_t nfds:监测的结构体的数组的大小。

int timeout:超时时间,到了这个时间没有异动发生,则返回  错误。一般填写  -1    表示永久等待

函数的返回值

        成功返回发生异动的事件的个数;

        失败返回  -1;

        超时返回 0;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小白菜123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值