1. 程式人生 > 實用技巧 >Linux網路程式設計TCP( 1 )——socket

Linux網路程式設計TCP( 1 )——socket

在學習主要程式碼之前先了解下TCP通訊兩端使用socket函式建立連線的流程:

1、客戶端和伺服器均使用socket函式各自建立一個套接字

2、伺服器用bind繫結IP地址和埠號

3、伺服器用listen開啟監聽模式

3、伺服器用accept阻塞自己,等待客戶端的連線請求

4、客戶端通過connect發出連線請求

5、伺服器收到連線請求後,建立連線,之後雙方可用recv(接收)和send(傳送)進行通訊

通訊結束後雙方通過close()關閉套接字

int socket(int domain,int type,int protocol);

引數:1、指明所用協議族 常用的有AF_INET AF_INET6 AF_LOCAL AF_ROUTE

      在TCP連線中一般使用AF_INET表示用ipv4和16位埠號

   2、套接字型別。SOCK_STREAM:TCP SOCK_DGRAM:UDP SOCK_RAW:允許對底層訪問

   3、協議類別。可以為0讓系統自動選擇

返回值若小於0說明發生錯誤,否則返回一個值表示建立套接字,類似每個人的身份證號一樣,

之後都用套接字描述符來形容這個值

int bind(int sockfd,const struct sockaddr*,socklen_t addrlen)

引數:1、套接字描述符

   2、協議地址,用於指定協議族、埠和IP地址

   3、第二個引數的長度

發生錯誤返回-1,繫結成功返回0; 該函式用於將某個套接字與協議地址關聯起來

int listen(int sockfd,int backlog)

引數:1、套接字描述符

   2、接受請求的最大長度

僅被伺服器呼叫,將套接字變為被動連線,將套接字變為監聽套接字,成功返回0,失敗返回-1

int accept(int sockfd, struct sockaddr* addr,socklen_t *addrlen);

引數:1、套接字描述符

   2、用於存放客戶端的協議地址資訊

   3、第二個引數的長度,注意,這裡不要直接用sizeof,會出錯。要定義一個socklen_t的變數。

伺服器阻塞式等待客戶端請求,成功連線後,客戶端相關資訊會被儲存到第二個引數裡。

失敗返回-1 成功返回客戶端的套接字描述符

int connect(int sockfd,struct sockaddr *addr,socklen_t *addrlen);

引數:1、套接字描述符

   2、伺服器的協議地址

   3、第二個引數的長度

客戶端發起連線請求並連線 成功返回0 失敗返回-1

int send(int sockfd,const void* msg,int len,int flags)

引數:1、傳送端套接字描述符

   2、傳送資料緩衝區

   3、第二個引數的長度

   4、0個或多個標誌的組合體,可直接設定為0 或用“|”連在一起。

    MSG_DONTWAIT:非阻塞操作

    MSG_DONTROUTE:告知網際層協議,目的主機在網路,不需要查詢路由表

    MSG_NOSIGNAL:動作不願被SIGPIPE訊號中斷

    MSG_OOB:表示接受到需要優先處理的資料

用於通訊間傳送資料

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

引數:1、接受端套接字描述符

   2、接受緩衝區基地址

   3、以位元組計算接受換乘區長度

   4、0或多個標誌的組合體

    MSG_DONTWAIT:設定非阻塞操作

    MSG_PEEK:接收資料後,在接收佇列保留原有資料

    MSG_WAITALL:阻塞操作

    MSG_OOB:表示接受到需要優先處理的資料

用於通訊接收資料

樣例:

客戶端

 1 #include<unistd.h>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<stdlib.h>
 5 #include<sys/socket.h>
 6 #include<arpa/inet.h>
 7 #include<netinet/in.h>
 8 #include<string.h>
 9 using namespace std;
10 int main()
11 {
12     int sockfd;
13     struct sockaddr_in sock_addr;
14     int i,j,op;
15     sockfd=socket(AF_INET,SOCK_STREAM,0);
16     if(sockfd<0)
17     {
18         printf("套接字建立失敗\n");
19         return -1;
20     }
21     bzero(&sock_addr,sizeof(sock_addr));
22     sock_addr.sin_family=AF_INET;
23     sock_addr.sin_port=htons(8000);
24     
25     op=connect(sockfd,(struct sockaddr*)&sock_addr,sizeof(sock_addr));
26     if(op<0)
27     {
28         printf("connect error\n");
29         close(sockfd);
30         return -1;
31     }
32 
33     while(1)
34     {
35         char buf[1010]="";
36         
37         fgets(buf,sizeof(buf),stdin);
38         send(sockfd,buf,strlen(buf),0);
39         //printf("send:%s\n",buf);
40         if((op=recv(sockfd,buf,strlen(buf),0))>0)
41         {
42             buf[op]='\0';
43             printf("%s\n",buf);
44         }
45     }
46     close(sockfd);
47     return 0;
48 }

伺服器:

伺服器端改用select實現非阻塞連線

  1 #include<iostream>
  2 #include<sys/socket.h>
  3 #include<arpa/inet.h>
  4 #include<netinet/in.h>
  5 #include<unistd.h>
  6 #include<cstdlib>
  7 #include<cstdio>
  8 #include<string.h>
  9 #include<pthread.h>
 10 #include<sys/select.h>
 11 #include<algorithm>
 12 #include<sys/time.h>
 13 #include<sys/types.h>
 14 using namespace std;
 15 
 16 int main()
 17 {
 18     int sockfd,sfd;
 19     struct sockaddr_in sock_addr;
 20     int i,j,op;
 21     int maxfd,maxi,n;
 22 
 23     fd_set rset,allset;
 24     int client[1024];
 25     char buf[100];
 26 
 27     sockfd=socket(AF_INET,SOCK_STREAM,0);
 28     if(sockfd<0)
 29     {
 30         printf("套接字建立失敗\n");
 31         return -1;
 32     }
 33 
 34     bzero(&sock_addr,sizeof(sock_addr));
 35     sock_addr.sin_family=AF_INET;
 36     sock_addr.sin_port=htons(8000);
 37     sock_addr.sin_addr.s_addr=htons(INADDR_ANY);
 38 
 39     op=bind(sockfd,(struct sockaddr*)&sock_addr,sizeof(sock_addr));
 40     if(op<0)
 41     {
 42         printf("套接字繫結失敗\n");
 43         close(sockfd);
 44         return -1;
 45     }
 46 
 47     op=listen(sockfd,4);//4表示套接字最大維護連線數目
 48     if(op<0)
 49     {
 50         printf("listen error\n");
 51         close(sockfd);
 52         return -1;
 53     }
 54     int clientfd;
 55     
 56     struct sockaddr_in client_addr;
 57     bzero(&client_addr,sizeof(client_addr));
 58     socklen_t len=sizeof(struct sockaddr);
 59 
 60     maxfd=sockfd;
 61     maxi=-1;
 62     for(i=0;i<1024;i++)
 63         client[i]=-1;
 64     
 65     FD_ZERO(&allset);
 66     FD_SET(sockfd,&allset);//構造監聽套接字檔案描述符
 67 
 68     while(1)
 69     {
 70         //sleep(5);
 71         rset=allset;
 72         op=select(maxfd+1,&rset,NULL,NULL,NULL);
 73         if(op<0)
 74         {
 75             cout<<"select error\n";
 76             return -1;
 77         }        
 78         
 79         if(FD_ISSET(sockfd,&rset))
 80         {
 81             printf("111111\n");
 82             clientfd=accept(sockfd,(struct sockaddr*)&client_addr,&len);
 83             printf("222222\n");
 84 
 85             if(clientfd<0)
 86             {
 87                 printf("accept error\n");
 88                 return -1;
 89             }
 90         
 91             char clientip[32]="";
 92             inet_ntop(AF_INET,&client_addr.sin_addr,clientip,16);
 93             printf("ip:%s,port:%d\n",clientip,ntohs(client_addr.sin_port));
 94 
 95             for(i=0;i<1024;i++)
 96             {    
 97                 if(client[i]<0)
 98                 {
 99                     client[i]=clientfd;
100                     break;
101                 }
102                 else cout<<clientfd<<endl;
103             }
104 
105             if(i==1024)
106             {
107                 cout<<"to many clients\n";
108                 return -1;
109             }
110 
111             FD_SET(clientfd,&allset);
112             if(clientfd>maxfd)
113                 maxfd=clientfd;
114             
115             maxi=max(maxi,i);
116 
117             if(--op==0)
118                 continue;
119         }
120         //sleep(5);
121         for(i=0;i<=maxi;i++)
122         {
123             sfd=client[i];
124             if(sfd<0)
125                 continue;
126             if(FD_ISSET(sfd,&rset))
127             {
128                 cout<<op<<endl;
129                 if((n=read(sfd,buf,90))==0)
130                 {
131                     cout<<"close"<<sfd<<endl;
132                     close(sfd);
133                     FD_CLR(sfd,&allset);
134                     client[i]=-1;
135                 }
136                 else if(n>0)
137                 {
138                     buf[n]='\0';
139                     cout<<"recv data:"<<buf<<endl;
140                     bzero(&buf,sizeof(buf));
141                     cout<<"send:";
142                     fgets(buf,sizeof(buf),stdin);
143                     send(sfd,buf,strlen(buf),0);
144                 }
145                 if(--op==0)
146                     break;
147             }
148         }
149         //cout<<"oooooooooooooooooooo"<<endl;
150     }
151     cout<<"wryyyyyyyyyyyyyyyyy"<<endl;
152     close(clientfd);
153     close(sockfd);
154     return 0;
155 }

參考書籍——《Linux網路程式設計》