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

  • 相关阅读:
    从Oracle提供两种cube产品说开
    Sql Server DWBI的几个学习资料
    Unload Oracle data into text file
    初学Java的几个tips
    我常用的Oracle知识点汇总
    benefits by using svn
    如何在windows上使用putty来显示远端linux的桌面
    building commercial website using Microsoft tech stack
    Understand Thread and Lock
    Update google calendar by sunbird
  • 原文地址:https://www.cnblogs.com/7qin/p/13510391.html
Copyright © 2011-2022 走看看