当前位置:   article > 正文

网络编程 -------- 3、TCP_UDP_UNIX

网络编程 -------- 3、TCP_UDP_UNIX

1、基于TCP的套接字编程流程 

    Server.c 
        socket 
        bind  (服务器的ip+端口)
        listen
        accept
        recv / send
        close

    Client.c 
        socket 
        connect (服务器的ip+端口)
        send / recv
        close

扩展:

        (1) 三路握手: TCP建立连接时
                1)SYN请求 (客户端-->服务器) 
                2)SYN+ACK应答 (服务器-->客户端) 
                3)ACK确认 (客户端-->服务器)


        (2) 四次挥手: TCP断开连接时 
                1)FIN请求 (客户端-->服务器)
                2)ACK应答 (服务器-->客户端)
                3)FIN请求 (服务器-->客户端)
                4)ACK应答 (客户端-->服务器)

2、基于UDP的套接字编程流程 

    Server.c 
        socket  
        bind  (服务器的ip+端口)
        recvfrom / sendto
        close

    Client.c 
        socket 
        //设置服务器的ip和端口
        sendto / recvfrom
        close

  1.             利用UDP 实现简单的通信   UDP ---> SOCK_DGRAM 数据报套接字类型
  2.                 udp_server.c   接收数据 
  3.                     int main( int argc, char *argv[] )
  4.                     {
  5.                         //1.创建套接字 UDP ---> SOCK_DGRAM 数据报套接字
  6.                         int server_fd = socket( AF_INET, SOCK_DGRAM, 0 );
  7.                         if( server_fd == -1 )
  8.                         {
  9.                             perror("socket server error ");
  10.                             return -1;
  11.                         }
  12.                         printf("server_fd = %d\n", server_fd );
  13.                         //2.绑定服务器的ip和端口
  14.                         struct sockaddr_in  server_addr;
  15.                         server_addr.sin_family = AF_INET;           //协议族 
  16.                         server_addr.sin_port = htons( atoi(argv[2]) );    //端口号
  17.                         inet_aton( argv[1], &server_addr.sin_addr );  //IP地址
  18.                         int re = bind( server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr) );
  19.                         if( re == -1 )
  20.                         {
  21.                             perror("bind server error ");
  22.                             return -1;
  23.                         }
  24.                         printf("bind server success\n");
  25.                         //3.通信 
  26.                         while( 1 )
  27.                         {
  28.                             //接收数据 
  29.                             char buf[128] = {0};
  30.                             struct sockaddr_in  client_addr;
  31.                             socklen_t len = sizeof(client_addr);
  32.                             re = recvfrom( server_fd, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &len );
  33.                             if( re >= 0 )
  34.                             {
  35.                                 printf("%s : %s\n", inet_ntoa(client_addr.sin_addr), buf );
  36.                             }
  37.                             else 
  38.                             {
  39.                                 perror("recvfrom server error ");
  40.                                 break;
  41.                             }
  42.                             //人为定义退出条件
  43.                             if( buf[0] == '#' )
  44.                             {
  45.                                 break;
  46.                             }
  47.                         }
  48.                         //4.关闭套接字
  49.                         close( server_fd );
  50.                     }
  51.                 udp_client.c   发送数据  
  52.                     int main( int argc, char *argv[] )
  53.                     {
  54.                         //1.创建套接字 UDP ---> SOCK_DGRAM 数据报套接字
  55.                         int client_fd = socket( AF_INET, SOCK_DGRAM, 0 );
  56.                         if( client_fd == -1 )
  57.                         {
  58.                             perror("socket client error ");
  59.                             return -1;
  60.                         }
  61.                         printf("client_fd = %d\n", client_fd );
  62.                         //2.设置服务器的ip和端口
  63.                         struct sockaddr_in  server_addr;
  64.                         server_addr.sin_family = AF_INET;           //协议族 
  65.                         server_addr.sin_port = htons( atoi(argv[2]) );    //端口号
  66.                         inet_aton( argv[1], &server_addr.sin_addr );  //IP地址
  67.                         //3.通信 
  68.                         while(1)
  69.                         {
  70.                             //发送数据 
  71.                             char buf[128] = {0};
  72.                             printf("input data : ");
  73.                             fgets(buf, sizeof(buf), stdin);
  74.                             int re = sendto( client_fd, buf, strlen(buf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr) );
  75.                             if( re == -1 )
  76.                             {
  77.                                 perror("sendto error ");
  78.                                 break;
  79.                             }
  80.                             //人为定义退出条件
  81.                             if( buf[0] == '#' )
  82.                             {
  83.                                 break;
  84.                             }
  85.                         }
  86.                         //4.关闭套接字
  87.                         close( client_fd );
  88.                     }

            

3、UNIX域协议

        UNIX域协议是利用socket编程接口 来实现 本地进程之间(客户端/服务器)的通信,它是进程间通信(IPC)的一种方式。它使用文件系统中的路径名来标识服务器和客户端。

        UNIX域协议的套接字: 
            SOCK_STREAM     --->  TCP 面向字节流 
            SOCK_DGRAM      --->  UDP 面向数据报  

        其编程接口 和 流程 与 ipv4协议族是一样的
        只不过 协议族为 AF_UNIX , 对应的地址结构体为 

            UNIX域协议地址结构体 ( man 7 unix )
                    #include <sys/un.h>

                struct sockaddr_un 
                {
                    sa_family_t  sun_family;        /* 协议族 AF_UNIX */
                    char         sun_path[108];     /* UNIX域协议的地址,在本地文件系统中的“绝对路径名” pathname */
                };

            #define UNIX_PATH  "/home/china/unix2418F"

        实现方法:  UDP / TCP 
       

  1. 练习: 
  2.             利用UNIX域协议 实现简单的通信 (以UDP为例)
  3.                 unix_server.c   接收数据 
  4.                     int main( int argc, char *argv[] )
  5.                     {
  6.                         //删除 
  7.                         unlink( UNIX_PATH );
  8.                         //1.创建套接字 AF_UNIX  
  9.                         int server_fd = socket( AF_UNIX, SOCK_DGRAM, 0 );
  10.                         if( server_fd == -1 )
  11.                         {
  12.                             perror("socket server error ");
  13.                             return -1;
  14.                         }
  15.                         //2.绑定 服务器的地址 
  16.                         struct sockaddr_un  server_addr;
  17.                         server_addr.sun_family = AF_UNIX;           //协议族 
  18.                         strcpy( server_addr.sun_path, UNIX_PATH );  //unix域协议的地址
  19.                         int re = bind( server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr) );
  20.                         if( re == -1 )
  21.                         {
  22.                             perror("bind server error ");
  23.                             close( server_fd );
  24.                             return -1;
  25.                         }
  26.                         printf("bind server success\n");
  27.                         struct sockaddr_un  client_addr;
  28.                         socklen_t len = sizeof(client_addr);
  29.                         //3.通信 
  30.                         while(1)
  31.                         {
  32.                             //接收数据 
  33.                             char buf[128] = {0};
  34.                             re = recvfrom( server_fd, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &len );
  35.                             if( re >= 0 )
  36.                             {
  37.                                 printf("recv : %s\n", buf );
  38.                             }
  39.                             else 
  40.                             {
  41.                                 perror("recvfrom server error ");
  42.                                 break;
  43.                             }
  44.                             
  45.                             if( buf[0] == '#' )
  46.                             {
  47.                                 break;
  48.                             }
  49.                         }
  50.                         //4.关闭套接字
  51.                         close( server_fd );
  52.                     }
  53.                 unix_client.c   发送数据  
  54.                     //1.创建套接字 
  55.                     //2.设置服务器的地址 
  56.                     //3.通信 
  57.                     //4.关闭套接字


4、套接字选项  

    套接字选项是用来设置或获取套接字的一些特性的选项。

        每个套接字在不同的层次上(级别) 有不同的行为属性(选项) 

        有两个接口函数用来 获取和设置 套接字的选项: 

            getsockopt 
            setsockopt  

                NAME
                    getsockopt, setsockopt - get and set options on sockets
                SYNOPSIS
                    #include <sys/types.h>          /* See NOTES */
                    #include <sys/socket.h>

                    int getsockopt(int sockfd, int level, int optname,
                                    void *optval, socklen_t *optlen);
                    int setsockopt(int sockfd, int level, int optname,
                                    const void *optval, socklen_t optlen); 
                        功能:获取/设置套接字的选项 
                        参数: 
                            sockfd:指定要操作的套接字描述符 
                            level:级别,不同的选择在不同的级别上(查看资料)
                            optname:选项名 
                            optval: 通用指针 
                                        get 用来保存获取到的选项值 
                                        set 用来保存要设置的选项值 
                                             不同的选项 对应的类型是不一样的 
                                                如果为 int  ---> 0  禁用选项 
                                                            --> 非0 使能选项 
                            optlen: 
                                    get 指针,指向空间保存选项值的空间的长度 
                                    set 变量,用来指定要设置的选项值的长度 
                        返回值: 
                            成功,返回0
                            失败,返回-1,同时errno被设置
                     

  1.             设置 端口号重用 
  2.                  选项名: SO_REUSEPORT 
  3.                  级别:  SOL_SOCKET
  4.                  值的类型: int 
  5.                  /设置端口号重用 
  6.                  int n = 1;
  7.                  setsockopt( server_sock, SOL_SOCKET, SO_REUSEPORT, &n, sizeof(n) );

5、UDP的例子 (拓展)

    1)DNS : Domain Name System 域名系统  

            www.baidu.com  ----> 域名  

            DNS:是把一个域名 转换成 相应的ip地址的服务  

            DNS协议 传输层用到UDP协议 
                    DNS Server  
                        ip: 114.114.114.114 
                        端口  53

  
    2)NTP : Network Time Protocol 网络时间协议

  
            基于UDP的传输层协议 

                服务器: 
                    阿里云 :  182.92.12.11
                    端口: 123      

  1. 利用TCP 写一个网络传输文件的程序  
  2.             file_tcp_server.c   服务器 接收文件  
  3.             file_tcp_client.c   客户端 发送文件  
  4.                 注意: 
  5.                     通信双方 发送和接收的 数据、大小、顺序 要保持一致 
  6.                     遵守通信双向的约定 ---> "协议"
  7.                 file_tcp_server.c   服务器 接收文件  
  8.                     int recv_file( int sock_fd )
  9.                     {
  10.                         //切换路径 
  11.                         chdir("../");
  12.                         //接收文件名的长度大小 
  13.                         int name_len = 0;
  14.                         int re = recv( sock_fd, &name_len, sizeof(name_len), 0 );
  15.                         if( re == -1 )
  16.                         {
  17.                             perror("recv name_len error "); 
  18.                             return -1;
  19.                         }
  20.                         printf("recv name_len success , len = %d\n", name_len );
  21.                         //接收文件名
  22.                         char filename[128] = {0};
  23.                         re = recv( sock_fd, filename, name_len, 0 );
  24.                         if( re == -1 )
  25.                         {
  26.                             perror("recv filename error ");
  27.                             return -1;
  28.                         }
  29.                         printf("recv filename success , filename = %s\n", filename );
  30.                         
  31.                         //接收文件的大小 
  32.                         int file_size = 0;
  33.                         re = recv( sock_fd, &file_size, sizeof(file_size), 0 );
  34.                         if( re == -1 )
  35.                         {
  36.                             perror("recv file_size error ");
  37.                             return -1;
  38.                         }
  39.                         printf("recv file_size success , file_size = %d\n", file_size );
  40.                         /* 接收文件的内容
  41.                             创建并打开文件
  42.                             接收数据
  43.                             写入文件
  44.                             关闭文件
  45.                         */
  46.                         //创建并打开文件
  47.                         int fd = open( filename, O_RDWR | O_CREAT | O_EXCL, 0666 );
  48.                         if( fd == -1 )
  49.                         {
  50.                             if( errno == EEXIST )  //文件已经存在,就直接打开即可
  51.                             {
  52.                                 fd = open( filename, O_RDWR | O_TRUNC );
  53.                             }
  54.                             else 
  55.                             {
  56.                                 perror("open file error ");
  57.                                 return -1;
  58.                             }
  59.                         }
  60.                         int write_size = 0;      //已经写入的字节数
  61.                         while( write_size < file_size )
  62.                         {
  63.                             //先接收数据 
  64.                             char buf[128] = {0};
  65.                             re = recv( sock_fd, buf, 100, 0 );
  66.                             if( re > 0 )
  67.                             {
  68.                                 //写入文件 
  69.                                 write( fd, buf, re );
  70.                                 write_size += re;
  71.                             }
  72.                             else 
  73.                             {
  74.                                 perror("recv file error ");
  75.                                 break;
  76.                             }
  77.                         }
  78.                         if( write_size == file_size )
  79.                         {
  80.                             printf("recv file success\n");
  81.                         }
  82.                         else 
  83.                         {
  84.                             printf("recv file failed \n");
  85.                         }
  86.                         
  87.                         //关闭文件 
  88.                         close( fd );
  89.                     }
  90.                     int main( int argc, char *argv[] )
  91.                     {
  92.                         //1.创建套接字 
  93.                         int server_fd = socket( AF_INET, SOCK_STREAM, 0 );
  94.                         if( server_fd == -1 )
  95.                         {
  96.                             perror("socket server error ");
  97.                             return -1;
  98.                         }
  99.                         printf("server_fd = %d\n", server_fd );
  100.                         //2.绑定 服务器的ip和端口
  101.                         struct sockaddr_in  server_addr;
  102.                         server_addr.sin_family = AF_INET;                   //协议族 
  103.                         server_addr.sin_port = htons( atoi(argv[2]) );    //端口号
  104.                         inet_aton( argv[1], &server_addr.sin_addr );     //IP地址
  105.                         //设置端口号重用
  106.                         int n = 1;
  107.                         setsockopt( server_fd, SOL_SOCKET, SO_REUSEPORT, &n, sizeof(n) );
  108.                         int re = bind( server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr) );
  109.                         if( re == -1 )
  110.                         {
  111.                             perror("bind server error ");
  112.                             close( server_fd );
  113.                             return -1;
  114.                         }
  115.                         printf("bind server success\n");
  116.                         //3.监听 
  117.                         re = listen( server_fd, 5 );
  118.                         if( re == -1 )
  119.                         {
  120.                             perror("listen server error ");
  121.                             close( server_fd ); 
  122.                             return -1;
  123.                         }
  124.                         printf("listen server success\n");
  125.                         //4.接受连接 
  126.                         struct sockaddr_in  client_addr;
  127.                         socklen_t len = sizeof(client_addr);
  128.                         int client_fd = accept( server_fd, (struct sockaddr *)&client_addr, &len );
  129.                         if( client_fd == -1 )
  130.                         {
  131.                             perror("accept error ");
  132.                             close( server_fd );
  133.                             return -1;
  134.                         }
  135.                         printf("client_fd = %d\n", client_fd );
  136.                         printf("client_ip = %s\n", inet_ntoa(client_addr.sin_addr) );
  137.                         //5.通信 -->接收文件 
  138.                         recv_file( client_fd );
  139.                         //6.关闭套接字 
  140.                         close( server_fd );
  141.                     }
  142.                 file_tcp_client.c   客户端 发送文件  
  143.                     int send_file( int sock_fd, char * filename )
  144.                     {
  145.                         //发送文件名的长度大小 
  146.                         int name_len = strlen(filename);
  147.                         int re = send( sock_fd, &name_len, sizeof(name_len), 0 );
  148.                         if( re == -1 )
  149.                         {
  150.                             perror("send name_len error ");
  151.                             return -1;
  152.                         }
  153.                         printf("send name_len success , len = %d\n", name_len );
  154.                         //发送文件名 
  155.                         re = send( sock_fd, filename, name_len, 0 );
  156.                         if( re == -1 )
  157.                         {
  158.                             perror("send filename error ");
  159.                             return -1;
  160.                         }
  161.                         printf("send filename success , filename = %s\n", filename );
  162.                         //发送文件的大小
  163.                         struct stat  st;
  164.                         stat( filename, &st );  //获取文件属性-->文件大小 
  165.                         int file_size = st.st_size;
  166.                         re = send( sock_fd, &file_size, sizeof(file_size), 0 );
  167.                         if( re == -1 )
  168.                         {
  169.                             perror("send file_size error ");
  170.                             return -1;
  171.                         }
  172.                         printf("send file_size success , file_size = %d\n", file_size );
  173.                         /* 发送文件的内容 
  174.                             打开文件
  175.                             读取
  176.                             发送 
  177.                             关闭文件 
  178.                         */
  179.                         //打开文件
  180.                         int fd = open( filename, O_RDONLY );
  181.                         if( fd == -1 )
  182.                         {
  183.                             perror("open file error ");
  184.                             return -1;
  185.                         }
  186.                         int read_size = 0;      //已经读取到的字节数
  187.                         while( read_size < file_size )
  188.                         {
  189.                             //先读取文件内容 
  190.                             char buf[128] = {0};
  191.                             re = read( fd, buf, 100 );
  192.                             if( re > 0 )
  193.                             {
  194.                                 //发送数据 
  195.                                 send( sock_fd, buf, re, 0 );
  196.                                 read_size += re;
  197.                             }
  198.                             else 
  199.                             {
  200.                                 perror("read file error ");
  201.                                 break;
  202.                             }
  203.                         }
  204.                         if( read_size == file_size )
  205.                         {
  206.                             printf("send file success\n");
  207.                         }
  208.                         else 
  209.                         {
  210.                             printf("send file failed \n");
  211.                         }
  212.                         //关闭文件 
  213.                         close( fd );
  214.                     }
  215.                     int main( int argc, char *argv[] )
  216.                     {
  217.                         //1.创建套接字 
  218.                         int client_fd = socket( AF_INET, SOCK_STREAM, 0 );
  219.                         if( client_fd == -1 )
  220.                         {
  221.                             perror("socket client error "); 
  222.                             return -1;
  223.                         }
  224.                         printf("client_fd = %d\n", client_fd );
  225.                         //2.设置服务器的ip和端口
  226.                         struct sockaddr_in  server_addr;
  227.                         server_addr.sin_family = AF_INET;                   //协议族 
  228.                         server_addr.sin_port = htons( atoi(argv[2]) );    //端口号
  229.                         inet_aton( argv[1], &server_addr.sin_addr );     //IP地址
  230.                         //3.连接服务器 
  231.                         int re = connect( client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr) );
  232.                         if( re == -1 )
  233.                         {
  234.                             perror("connect error ");
  235.                             close( client_fd );
  236.                             return -1;
  237.                         }
  238.                         printf("connect success\n");
  239.                         //4.通信 --> 发送文件 
  240.                         send_file( client_fd, argv[3] );
  241.                         
  242.                         //5.关闭套接字
  243.                         close( client_fd );
  244.                     }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/918212
推荐阅读
相关标签
  

闽ICP备14008679号