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