1. 程式人生 > >Linux socket編程示例(最簡單的TCP和UDP兩個例子)

Linux socket編程示例(最簡單的TCP和UDP兩個例子)

步驟 proto 詳解 dto 應該 pro sock bind ram

一、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("連接服務器成功....\n");
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\n", buf);
47
48 /*關閉連接*/
49 close(sockfd);
50 return 0;
51 }
復制代碼

復制代碼
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端口,等待客戶端連接...\n",
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\n",
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\n",
66 count, buf);
67 char *str = "歡迎你客戶端";
68 send(clientfd, str, strlen(str), 0);
69 /*關閉連接*/
70 close(clientfd);
71 close(sockfd);
72 return 0;
73 }
復制代碼
五、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\n", buf);
39 close(sd);
40 }
復制代碼

復制代碼
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\n",
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 }

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

Linux socket編程示例(最簡單的TCP和UDP兩個例子)