zoukankan      html  css  js  c++  java
  • Linux socket编程示例

    一、socket编程

       网络功能是Uinux/Linux的一个重要特点,有着悠久的历史,因此有一个非常固定的编程套路。

      基于TCP的网络编程:

        基于连接, 在交互过程中, 服务器和客户端要保持连接, 不能断开。重发一切出错数据、数据验证, 保证数据的正确性、完整性和顺序性,

        缺点是消耗的资源比较大。

      基于UDP的网络编程:

        无连接协议, 在网络交互过程中不保持连接, 只需要在发送数据时连接一下, 不重发、验证数据。优点是资源消耗少, 数据的可靠性完整性

        顺序性得不到保证。

    二、编程步骤:

        服务器:

          ①  创建socket(套接字)   socket()

          ②  准备通信地址

          ③  将创建的socket和通信地址绑定   bind()

          ④  监听端口   listen()

          ⑤  等待客户端连接   accpet()

          ⑥  通信双方收发数据  read()/write()

                      send()/recv()

          ⑦  关闭socket

        客户端:

          ①  创建socket(套接字)  socket()

          ②  准备通信地址

          ③  连接服务器  connect()

          ④  收发数据  read()/write()

                  send()/recv()

          ⑤  关闭socket  

    三、API详解

      ①  socket()函数

        int  socket(domain, type, protocol)

        domain: 

            AF_UNIX/AF_LOCAL/AF_FILE: 本地通信

            AF_INET: 网络通信 ipv4

            AF_INET6: 网络通信 ipv6

            注:如果AF换成PF效果一样

        type, 选择通信类型, 主要包括:

            SOCK_STREAM: TCP 

            SOCK_DGRAM : UDP

        protocol, 本来应该指定通信协议, 但现在基本废弃, 因为协议已经在前面两个参数指定完成,给0即可

       ②  bind()函数

        int bind(int sockfd, struct sockaddr *addr, size)

        sockfd: 要绑定的套接字描述符

        size:  第二个参数占据的内存空间大小

        addr:  涉及三个数据结构struct sockaddr, sockaddr_un, sockaddr_in

          sockaddr,  主要用于函数参数, 不负责存储数据

          sockaddr_un,  当着本地通信时, 用于本地通信使用的地址  (sys/un.h)

          sockaddr_in,  当着网络通信时, 负责存储网络通信的地址数据

          struct sockaddr_in {

              sin_family;  //用于指定协议族, 和socket()的参数保持一致

              sin_port;    //网络通信使用的端口号  

              sin_addr; //存储网络通信的ip地址 

          }          

      ③ htons

      ④ inet_aton         

      ⑤ listen()函数

        int listen(int sockfd, int backlog)

         sockfd: 将sockfd参数所标识的套接字为被动模式, 使之可以接受连接请求

         backlog: 表示未决连接请求队列的最大长度, 即允许最多有多少个未决连接请求存在。若服务器的未决连接请求已达到该值, 则客户端通过                                                    connect()连接服务器的操作将返回-1,且error为ECONNREFUSED

      ⑥ accpet()函数

        int accpet(sockfd, struct sockaddr* addr, socklen_t *addrlen)

         从sockfd参数所标识套接字对应未决连接请求队列中取出的一个连接请求, 同时创建一个新的套接字,用于该连接通信, 返回套接字的描述符

           addr和addrlen 用于输出连接请求发起者的地址信息

         返回值: 为新创建用于和客户端通信的套接字描述符   失败-1, error  

      ⑦ inet_ntoa

      ⑧ recv()函数   

        int recv(int sockfd, buf, len, flags)

         flags, 通常取0:  阻塞收取数据

            O_NONBLOCK: 不阻塞, 如果未收到数据, 返回错误信息

         返回值:

            >0, 实际接受数据字节数

            -1 ,  出错, error

             0 ,  通信的另一端关闭

      ⑨ send()函数

       int send(int sockfd, buf, len, flags)

         flags: 通常取0, 阻塞发送

         O_NONBLOCK: 不阻塞, 如果未收到数据, 返回错误信息

      ⑩ connect()函数

       int connect(int sockfd, addr, addr_len)

         参数参考bind()      

     四、TCP示例

     1 /*******************************
     2     client.c
     3 ********************************/
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 #include <string.h>
     7 #include <unistd.h>
     8 #include <sys/types.h>
     9 #include <sys/socket.h>
    10 #include <netinet/in.h>
    11 #include <arpa/inet.h>
    12 #define PORT 8888
    13 
    14 int main()
    15 {
    16     /*1 创建socket*/
    17     int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    18     if(sockfd == -1)
    19     {
    20         perror("socket failed");
    21         exit(-1);
    22     }
    23     /*2 准备通信地址*/
    24     struct sockaddr_in addr;
    25     addr.sin_family = AF_INET;
    26     /*设置为服务器进程的端口号*/
    27     addr.sin_port    = htons(PORT);
    28     /*服务器所在主机IP地址*/
    29     inet_aton("192.168.182.10", &addr.sin_addr);
    30     
    31     /*3 连接服务器*/
    32     int res = connect(sockfd, 
    33                       (struct sockaddr *)&addr,
    34                       sizeof(addr));
    35     if(res == -1)
    36     {
    37         perror("connect failed");
    38         exit(-1);
    39     }
    40     printf("连接服务器成功....
    ");
    41     /*4 和服务器交换数据*/
    42     char buf[100] = {0};
    43     char *str = "借点钱可以吗...";
    44     write(sockfd, str, strlen(str))    ;
    45     read(sockfd, buf, sizeof(buf));
    46     printf("服务器说:%s
    ", buf);
    47 
    48     /*关闭连接*/
    49     close(sockfd);
    50     return 0;
    51 }
    View Code
     1 /************************************
     2     server.c
     3 *************************************/
     4 
     5 #include <stdio.h>
     6 #include <stdlib.h>
     7 #include <string.h>
     8 #include <unistd.h>
     9 #include <sys/types.h>
    10 #include <sys/socket.h>
    11 #include <netinet/in.h>
    12 #include <arpa/inet.h>
    13 #define PORT 8888
    14 
    15 int main()
    16 {
    17     /*1 创建socket*/
    18     int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    19     if(sockfd == -1)
    20     {
    21         perror("socket failed");
    22         exit(-1);
    23     }
    24     /*2 准备通信地址*/
    25     struct sockaddr_in addr;
    26     addr.sin_family = AF_INET;
    27     addr.sin_port    = htons(PORT);
    28     inet_aton("192.168.182.10", &addr.sin_addr);
    29     
    30     /*3 绑定socket和通信地址*/
    31     int res = bind(sockfd,(struct sockaddr *)&addr,
    32                        sizeof(addr));
    33     if(res == -1)
    34     {
    35         perror("bind failed");
    36         exit(-1);
    37     }
    38     /*4 监听端口*/
    39     res = listen(sockfd, 100);
    40     if(res == -1)
    41     {
    42         perror("listen failed");
    43         exit(-1);
    44     }
    45     printf("开始监听%d端口,等待客户端连接...
    ",
    46             PORT);
    47     /*5 处理接收客户端的连接请求*/
    48     //用于保存客户端地址信息
    49     struct sockaddr_in fromaddr;
    50     /*len 取0会是什么效果?*/
    51     socklen_t len = sizeof(fromaddr);
    52     int clientfd = accept(sockfd, 
    53                     (struct sockaddr *)&fromaddr,
    54                     &len);
    55     if(clientfd == -1)
    56     {
    57         perror("accept failed");
    58         exit(-1);
    59     }
    60     printf("有一个客户端连接到服务器,它是:%s
    ",
    61             inet_ntoa(fromaddr.sin_addr));
    62     /*6 处理客户端数据*/
    63     char buf[100] = {0};
    64     int count = recv(clientfd, buf, sizeof(buf),0);
    65     printf("从客户端读取到%d字节:%s
    ",
    66             count, buf);
    67     char *str = "欢迎你客户端";
    68     send(clientfd, str, strlen(str), 0);
    69     /*关闭连接*/
    70     close(clientfd);
    71     close(sockfd);
    72     return 0;
    73 }
    View Code

     五、UDP示例

     1 /********************************
     2     UDP_client.c
     3 *********************************/
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 #include <string.h>
     7 #include <unistd.h>
     8 #include <sys/types.h>
     9 #include <sys/socket.h>
    10 #include <netinet/in.h>
    11 #include <arpa/inet.h>
    12 
    13 #define PORT 12345
    14 int main()
    15 {
    16     /*1 创建socket*/    
    17     int sd = socket(PF_INET, SOCK_DGRAM, 0);
    18     if(sd == -1)
    19     {
    20         perror("socket failed");
    21         exit(-1);
    22     }
    23     /*2 准备地址*/
    24     struct sockaddr_in addr;
    25     addr.sin_family = PF_INET;
    26     addr.sin_port = htons(PORT);
    27     inet_aton("192.168.182.10",  &addr.sin_addr);
    28     /*3 进行通信*/
    29     char *str = "借点钱可以吗";
    30     sendto(sd, str, strlen(str), 0,
    31             (struct sockaddr *)&addr,
    32             sizeof(addr));
    33     char buf[100] = {0};
    34     int len = sizeof(addr);
    35     recvfrom(sd, buf, sizeof(buf), 0,
    36             (struct sockaddr *) &addr,
    37               &len);
    38     printf("服务器说:%s
    ", buf);
    39     close(sd);
    40 }
    View Code
     1 /********************************
     2     UDP_server.c
     3 *********************************/
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 #include <string.h>
     7 #include <unistd.h>
     8 #include <sys/types.h>
     9 #include <sys/socket.h>
    10 #include <netinet/in.h>
    11 #include <arpa/inet.h>
    12 
    13 #define PORT 12345
    14 int main()
    15 {
    16     /*1 创建socket*/    
    17     int sd = socket(PF_INET, SOCK_DGRAM, 0);
    18     if(sd == -1)
    19     {
    20         perror("socket failed");
    21         exit(-1);
    22     }
    23     /*2 准备地址*/
    24     struct sockaddr_in addr;
    25     addr.sin_family = PF_INET;
    26     addr.sin_port = htons(PORT);
    27     inet_aton("192.168.182.10",  &addr.sin_addr);
    28     /*3 socket addr 绑定*/
    29     int res = bind(sd, (struct sockaddr *)&addr,
    30                     sizeof(addr));
    31     if(res == -1)
    32     {
    33         perror("bind failed");
    34         exit(-1);
    35     }
    36     /*4 进行通信*/
    37     while(1)
    38     {
    39         char buf[100] = {0};
    40         struct sockaddr_in fromaddr;
    41         int len = sizeof(fromaddr);
    42         recvfrom(sd, buf, sizeof(buf), 0,
    43                  (struct sockaddr *) &fromaddr,
    44                  &len);
    45         printf("从客户端%s接收到数据:%s
    ",
    46                 inet_ntoa(fromaddr.sin_addr),
    47                 buf);
    48         char *str = "没问题,借多少";
    49         sendto(sd, str, strlen(str), 0,
    50                 (struct sockaddr *)&fromaddr,
    51                 sizeof(fromaddr));
    52     }
    53     close(sd);
    54 
    55 }
    View Code

     

    https://www.cnblogs.com/jiangson/p/5977601.html

  • 相关阅读:
    2021 省选颓记
    题解 UVA12459 Bees' ancestors
    题解 UVA10812 Beat the Spread!
    题解 UVA12230 过河 Crossing Rivers
    题解 P1850 [NOIP2016 提高组] 换教室
    题解 P1297 [国家集训队]单选错位
    CSP2020 游记
    学习笔记10-18
    【题解-SP1724 TRICOUNT】简单易懂的递推式写法
    题解:论如何利用 大 模 拟 吊打LGJ~
  • 原文地址:https://www.cnblogs.com/7qin/p/13510391.html
Copyright © 2011-2022 走看看