linux网络编程

Posted 学无止境

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux网络编程相关的知识,希望对你有一定的参考价值。

A: osi七层:

           应用层                     

   表示层                     

   会话层                     

   ********************************

   传输层                       

   网络层                       

   数据链路层                   

   物理层

 

a1: 传输层协议:

             tcp(传输控制协议):可靠的,面向连接的(连接,通信,断开连接)

    ** tcp连接(三次握手连接)

   tcp四次握手连接

 udp(用户数据报协议):面向无连接,不安全

 端口号(默认80):找到接收数据的地址

                           IP:找到接收数据的机器

 

a2: 网络层协议:ip(网际协议)

 

a3: 数据链路层标准:以太网

 

 

 

B: 主机字节序和网络字节序:

        低位存放低地址,小端对齐(主机字节序)

低位存放高地址,大端对齐(网络字节序),使用htonl,htons,ntohs,ntohl函数,h:host     to:change        n:network      s:short       l:long

 

 

 

C: IP地址的转换:

        字符串类型:192.168.2.123

数值类型:

    in_addr_t inet_addr(const char *cp);

   功能:将字符串类型ip地址转换为数值型ip地址,并且转换字节序

   参数:cp----字符串类型ip地址

   返回值:数值型ip地址

 

in_addr_t inet_network(const char *cp);

               功能、参数、返回值同上,不同的是未做字节序转换

 

char *inet_ntoa(struct in_addr in);

               功能:将数值类型ip地址转为字符串型ip地址

   参数:in     

         struct in_addr

 {

  in_addr_t s_addr;

 };

 

 

 

D: 文件描述符:

       open  close  read  write  //linux提供的系统调用

   分配原则:当前系统最小,并空闲的

 

   ssize_t read(int fd, void *buf, size_t count);

     功能:从文件读取内容

 参数:fd----文件描述符

       buf----存放读取数据的缓冲区

   count----缓冲区的大小

 返回值:读取的字节数     0----读取结束    -1----失败

 

   ssize_t write(int fd, const void *buf, size_t count);

         功能:往文件写入数据

 参数:fd----文件描述符

       buf----写入数据的缓冲区

   count----缓冲区的大小

 返回值:写入数据的字节数    -1-----失败

 

 

 

E: 被动端/服务端函数:

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

      功能:创建网络版的文件描述符(套接字)

  参数:domain-----AF_INET(ipv4协议族)

        type-----套接字的类型   SOCK_STREAM=面向连接(tcp协议)               SOCK_DGRAM=面向无连接(udp协议)

        protocol:协议    0---根据协议族和套接字类型自动填写协议

                  或者:IPPROTO_TCP  IPPROTO_UDP

   返回值:套接字      -1-----失败

 

 

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

      功能:将IP地址和端口号与套接字绑定

       接收者:只能接收绑定地址为目的地址,绑定端口号为目的端口号的报文

   发送者:设置源ip地址和源端口号

  参数:sockfd----套接字

        addr:

     struct sockaddr_in {

        short sin_family;   //协议族:AF_INET

     short sin_port;   //端口号

     short in_addr sin_addr;   //ip地址

     }

addrlen------地址结构体的长度

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

 

 

e3:   int listen(int sockfd, int backlog);

          功能:将套接字的状态修改为被动态,并建议设置内核中的完成连接队列的长度

  参数:sockfd----套接字

        backlog----建议值

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

 

 

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

          功能:阻塞函数,从内核的连接完成队列中取出一个连接状态

  参数:sockfd----套接字

        addr----出参,带回主动端的ip地址和端口号

addrlen------地址结构体的长度

  返回值:用于通信的套接字    -1----失败   

 

 

 

F: 主动端/客户端函数:

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

 

 

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

          功能:发起三次握手连接

      参数:sockfd----套接字

            addr---被动端的ip地址和端口号

    addrlen----地址结构体长度

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

 

注意:

     read读取tcp数据时返回值为0表示写端/发送端关闭

 当接收端关闭,发送数据端将被信号SIGPIPE杀死

 

 

 

H: 接收数据(属性都默认是0):

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

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

 

 

 

I: 线程操作时注意:

       临界资源(多个进程(共享内存)或线程访问的资源(局部变量、全局变量))和互斥(在同一时间只有并仅有一个进程或线程可以访问临界资源)

 

 

 

J: 多路IO:

   j1: select监听的步骤:

          1.将监听的文件描述符添加到文件描述符集合 中

      eg:fd_set rdfds;

      FD_ZERO(&rdfds);

  FD_SET(0,&rdfds);

  FD_SET(confd,&rdfds);

   2.调用select监听活跃的文件描述符

   3.判断监听的文件描述符是否活跃

       eg:FD_ISSET(0,&rdfds);

 

 

           int select(int nfds,

      fd_set *readfds,

  fd_set *writefds,

  fd_set *exceptfds,

  struct timeval *timeout);

   功能:监听多个I/O端口(文件描述符),采用轮询的方式监听文件描述符,所以随着监听的文件描述符的增多而使效率降低

   参数:nfds---监听文件描述符中的最大值+1

         readfds、writefds、exceptfds(执行的文件描述符)---监听的文件描述符的集合。这三个文集描述符既是入参(监听的文件描述符集合),也是出参(带回活跃的文件描述符集合)

 timeout----监听超时的时间

返回值:监听文件描述符集合中活跃的文件描述符的个数        -1-----失败

 

      

操作文件描述符集合:

 

  将文件描述符fd从文件描述符集合set中删除:

void FD_CLR(int fd, fd_set *set);

 

  判断文件描述符fd在文件描述符集合set中:

int  FD_ISSET(int fd, fd_set *set);

   1----存在   0------不存在

 

  将文件描述符fd添加到文件描述符集合set中:

void FD_SET(int fd, fd_set *set);

  将文件描述符集合set清空:

void FD_ZERO(fd_set *set);

 

   j2: poll()工作模式和select相同---轮询监听:

      

       int poll(struct pollfd fds[],

            nfds_t nfds,

int timeout);

  参数:fds---监听的文件描述符的数组

   struct pollfd {

   int   fd;         /*监听的文件描述符*/

   short events;     /*感兴趣的事件*/

   short revents;    /*活跃的事件*/

  };

        nfds---数组的个数

timeout---超时时间,不超时就是 -1

   返回值:监听文件描述符集合中活跃的文件描述符的个数        -1----    -失败

 

 

   j3: epoll():

          工作模式:只关心活跃的文件描述符,所以它不会随着监听文件描述符的增多而效率下降

 

            int epoll_create(int size);

   功能:创建epoll文件描述符

   参数:size----epoll通知内核epoll最多监听的文件描述符的个数

   返回值:返回文件描述符     -1-----失败

 

 

int epoll_ctl(int epfd,

              int op,

  int fd,

  struct epoll_event *event);

功能:epoll操作监听的文件描述符

参数:epfd----epoll文件描述符

      op----操作:EPOLL_CTL_ADD(将文件描述符添加到epoll中)

              EPOLL_CTL_MOD(修改在epoll监听的文件描述符的事件)

  EPOLL_CTL_DEL(将文件描述符从epoll中删除)

  fd----要操作的文件描述符

  event:

        struct epoll_event {

__uint32_t   events;    /*感兴趣的事件*/

epoll_data_t data;        /*私有数据*/

};

typedef union epoll_data {

void        *ptr;

int          fd;

__uint32_t   u32;

__uint64_t   u64;

} epoll_data_t;

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

 

 

 int epoll_wait(int epfd,

                struct epoll_event *events,

int maxevents,

int timeout);

功能:监听文件描述符,并带回活跃的文件描述符

参数:epfd----epoll文件描述符

      events------出参,带回多个活跃的文件描述符的数组

  maxevents---最多可以带回多少个活跃的文件描述符

  timeout-----超时时间

返回值:活跃的文件描述符的个数    -1---失败   0----超时

 

 

 

K: 处理“addr already in use”问题:

       setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(int));

 

 

 

L: UDP的函数:

l1: int socket(AF_INET, SOCK_DGRAM, int 0);

 

l2: ssize_t sendto(int sockfd,

                    const void *buf,

size_t len,

int flags,

                    const struct sockaddr *dest_addr,

socklen_t addrlen);

功能:发送udp数据

参数:sockfd----套接字

      buf------发送数据

  len-----数据的长度

  flags-----0--->默认属性

  dest_addr:目的端的ip地址和端口号

  addrlen:地址结构体长度

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

 

l3:  ssize_t recvfrom(int sockfd,

                       void *buf,  

   size_t len,

   int flags,

                       struct sockaddr *src_addr,

   socklen_t *addrlen);

 功能:接收数据

 参数:sockfd----套接字

       buf----接收数据的缓冲区

   len----缓冲区的长度

   flags----0-->默认属性

   src_addr----出参,带回发送端的ip地址和端口号

   addrlen:地址结构体的长度

  返回值:收到的信息   -1---失败

 

注意:

     udp中只要调用recvfrom,就必须设置源端口号(bind)

 

 

 

M: udp广播:

      打开广播功能:

      setsockopt(sockfd,

             SOL_SOCKET,

             SO_BROADCAST,

             &on,

             sizeof(int));      192.168.2.255

 

 

 

N: 组播(多播):

      组播ip地址:224.0.0.0~239.255.255.255

 

  特殊的组播地址:

      224.0.0.1:所有具有组播功能的节点(主机   路由器)

  224.0.0.2:所有具有组播功能的路由器

 

  支持组播功能的命令:

      route add -net 224.0.0.0 netmask 240.0.0.0 dev em1(em1---连接网卡的名称)

 

  将本机IP地址添加到组播地址中:

      setsockopt(sockfd,

             IPPROTO_IP,

 IP_ADD_MEMBERSHIP,

 &mreq,

 sizeof(struct ip_mreq));

 

  struct ip_mreq

  {

       struct in_addr imr_multiaddr;   //组播地址

struct in_addr imr_interface;   //本机地址

  };

 

 

 

O: 关闭防火墙:

      # service iptables stop   //临时关闭防火墙

  #chkconfig iptables off

 

 

  #vim /etc/selinux/config 修改SELINUX = disabled

 

 

 

P: 登录:

       char *getpass(const chat *prompt);

       功能:接收密码

       参数:prompt-----提示信息

       返回值:接收的密码

 

   struct spwd *getspnam(const char *name);

        功能:根据用户名name返回/etc/shadow文件的内容

 

       char *crypt(const char *key, const char *salt);

        功能:将key加密

参数:key----明码

      salt-----参照

返回值:加密后的密码

 

 

 

Q: ftp功能:

    1.登录(服务器端的系统用户名称和密码)

2.pwd:显示服务器端当前的操作目录

       用户登录成功后的路径:登录用户的家目录

3.cd:切换命令的名称(../..)

      cd命令的结果:250 Directory successfully changed.

                550 Failed to change directory.

4.ls:浏览服务器端的当前目录下的内容

      ls命令的结果:文件类型、文件权限、硬链接数、用户id、用户组的id、大小、时间、文件名称

5.get:从服务器端下载文件,下载的文件存放到当前登录服务器的目录下

6.put:将客户端的文件上传到服务器端上,存放上传文件的目录是当前服务器的目录

    7.quit:客户端结束运行

 

  

  客户端功能:

      接收命令和参数,将命令和参数发送给服务器,并等待命令的结果

命令:enum ftp_cmd

      {

   CMD_LOGIN,

CMD_PWD,

CMD_CD,

CMD_LS,

CMD_PUT,

CMD_GET,

CMD_QUIT,

CMD_MAX

  };

 

 struct arg_login

 {

  char login_user[512];

char login_pwd[512];

 };

 

          struct cli_to_ser

  {

   int ftp_cmd;   //命令

union

{

struct arg_login argLogin;

char argCd[1024];

char argGet[1024];

char argPut[1024];

}ftp_arg;

  };

等待结果:struct ser_to_cli

  {

   int result;   //0---登录成功   -1----失败   -2---Failed to change directory.      1----Directory successfully changed.   2---ls命令完毕   3--get/put失败

           char string_result[512];

  };

 

 

  服务器功能:1.接收进程-----负责接收数据

              |    struct recv_to_opt

  |    {

   (无名管道) |   struct cli_to_ser data;

  | struct sockaddr_in cli_addr;

  |   };

              2.处理进程-----负责查看客户端是否以前登录过服务器,如果没有登录服务器,则记录客户端的登录信息,并创建子进程为客户端服务。如果登录过服务器,直接将数据封装完毕后发送给客户端对应的子进程。

  |

  | (每个子进程---处理进程:创建一个众所周知的管道)          

  |  或者

  |  (消息队列)

  |

  3.子进程集----负责处理命令,并将处理结果发送给对应的客户端

 

 

注意:

    1.文件传输时使用tcp,客户端是被动端,服务器端子进程是主动端

2.当服务器端子进程接收到quit命令时,子进程将登录表中的客户端对应的信息删除,子进程向客户端发送quit命令执行成功,子进程消亡,该子进程的父进程一定为其收尸,避免僵尸进程。

 

 

  客户端登录表(临界资源,在共享内存---互斥(信号量)中开辟空间,以数组的方式存储):

     struct cli_login_table

 {

  struct in_addr cli_addr;

pid_t child_pid;

 };

      

 

 

R: ipv6:

    1.查看是否有ipv6模块

        lsmod | grep ipv6   

2.开启ipv6功能:

    vim /etc/sysconfig/network--------》NETWORKING_IPV6=yes

3.ipv6的地址:

    ipv4的地址长度是32b(4个bytes)

ipv6的地址长度是128b(16个bytes)

     fe80::d6be:d9ff:fed4:90be/64-----64区分网络段和主机段,所以ipv6没有子网掩码

4.特殊的ipv6地址:

     0:0:0:0:0:0:0:0------>INADDR_ANY

 ::1--------->127.0.0.1

5.临时设置ipv6地址

     ifconfig em1 add ipv6地址

  长久设置:

     vim /etc/sysconfig/network-scripts/ifcfg-em1---------》IPV6INIT=yes   IPV6ADDR=IPV6地址

6.ipv6地址结构体

     struct sockaddr_in6

 {

  sin6_family;

sin6_port;

sin6_addr;

 };

 

 

 

S: unix域套接字(不是协议):

       应用于:进程间通信

   协议族:AF_LOCAL

   地址结构体:struct sockaddr_un

       {

short sun_family;   //AF_LOCAL--tcp   AF_UNIX---udp

char sun_path[];   //地址就是一个文件

   };

计算地址结构体的长度:SUN_LEN(&address);

 

 

 

T: 设置tags文件:

  1.进入要设置tags的目录

  2.生成tags文件:ctags -R

  3.把tags文件添加到vim中:vim /etc/vimrc 加入 set tags=/usr/include/tags

以上是关于linux网络编程的主要内容,如果未能解决你的问题,请参考以下文章

Linux高级网络编程系列教程

linux怎么配置网络设置(linux怎么配置网络 连接外网)

linux 查看当前的网络配置

linux网络设置

理解 Linux 网络栈 (Linux networking stack):Linux 网络协议栈简单总结

Kali Linux该怎么进行网络配置