TCP之socket編程

socket(套接字):IP地址+端口號,唯一標識網絡中的一個進程

socket編程中建立連接的兩個進程都有一個socket來標識唯一一個連接。

網絡字節序:網絡數據流有大小端之分,發送主機通常將發送緩衝區中的數據按內存地址從低到高的順序發出,接收主機把從網絡上接到的字節依次保存在接收緩衝區中,也是按內存地址從低到高的順序保存,網絡數據流的地址規定:先發出的數據是低地址,後發出的數據是

地址。 

TCP/IP協議規定,網絡數據流應採用大端字節序,即低地址高字節。

例:如果端口號是1000(0x3e8),則地址0是0x03,地址1是0xe8, 也就是先發0x03,再發0xe8,這16位在發送主機的緩衝區中也應該是低地址存0x03,高地址存0xe8。但是,如果發送主機是小端字節序的,這16位端口號被解釋成0xe803,不是1000。因此,發送主機把1000填到發送緩衝區之前需要做字節序的轉換。同樣地,接收主機如果是小端字節序的, 接到16位的源端口號也要做字節序的轉換。如果主機是大端字節序的,發送和接收都不需要做轉換。同理,32位的IP地址也要考慮網絡字節序和主機字節序的問題。

服務器端socket:

1.創建套接字:int socket(int domain,int type,int protocol) //domain底層採用何種協議,傳輸類型,TCP面向字節流式

2.使用struct socketaddr_in 結構體填充網絡方面信息

3.綁定:將套接字信息填充到內核中

4.設置套接字狀態爲監聽狀態,接收客戶端發來的連接請求

5.等待客戶請求,當請求連接來後,接受連接請求,返回一個新的對應於此次連接的套接字(accept)

6.新的套接字和客戶端進行通信

accept函數:在一個套接口接受一個連接。

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

 sockfd和 listen() 中套接字描述符相同。addr要求接入的信息所要去的地方。返回值:如果執行成功,返回值爲0,否則設置錯誤碼,返回-1。


bind函數:將一本地地址與一套接口捆綁。

int bind(int sockfd, const struct sockaddr* addr, socklen_t len);

適用於未連接的數據報或流類套接口,在connect()listen()調用前使用。當用socket()創建套接口後,它便存在於一個名字空間(地址族)中,但並未賦名。bind()函數通過給一個未命名套接口分配一個本地名字來爲套接口建立本地捆綁(主機地址/端口號

服務器端代碼:

 1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/socket.h>
  6 #include<netinet/in.h>
  7 #include<arpa/inet.h>
  8 #include<pthread.h>
  9 int start(int _port,char* ip)
 10 {   
 11     //1.create sock
 12     int listen_sock=socket(AF_INET,SOCK_STREAM,0);
 13     if(listen_sock < 0){
 14         perror("sock");
 15         exit(1);
 16     }
 17     //2.fill information 
 18     struct sockaddr_in local;
 19     local.sin_family=AF_INET;
 20     local.sin_port=htons(_port);
 21     local.sin_addr.s_addr=inet_addr(ip);
 22     //3.bind
 23     if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0)
 24     {
 25         perror("bind");
 26         exit(2);
 27     }
 28     //4.set listen 
 29     if(listen(listen_sock,5)<0)
 30     {
 31         perror("listen");
 32         exit(3);
 33     }
 34     return listen_sock;
 35 
 36    
 37 }
 38 void usage(const char *proc)
 39 {   
 40     printf("usage:%s [ip] [port]\n",proc);
 41 }
 42 
 43 void* thread_run(void* arg)
 44 {
 45     int sock =(int)arg;
 46     char buf[1024];
 47     while(1)
 48     {
 49         memset(buf,'\0',sizeof(buf));
 50         ssize_t _size=read(sock,buf,sizeof(buf)-1);
 51         if(_size<0)
 52         {
 53             printf("read fail...\n");
 54             exit(1);
 55         }else if(_size==0)
 56         {
 57             printf("closed connect...\n");
 58             exit(2);
 59         }else
 60         {
 61             printf("client# %s\n",buf);
 62         }
 63     }
 64 }
 65 
 66 int main(int argc,char* argv[])
 67 {
 68     if(argc!=3)
 69     {
 70         usage(argv[0]);
 71         exit(1);
 72     }
 73     int listen_sock=start(atoi(argv[2]),argv[1]);
 74     struct sockaddr_in client;
 75     socklen_t len=sizeof(client);
 76     int done=0;
 77     while(!done)
 78     {
 79         int new_sock=accept(listen_sock,(struct sockaddr*)&client,&len);
 80         if(new_sock<0)
 81         {
 82             perror("accept");
 83             continue;
 84         }
 85         printf("get a connect... [sock]:%d [ip]:%s [port]:%d\n",new_sock,inet_ntoa(cl ient.sin_addr),ntohs(client.sin_port));
 86    
 87 #ifdef _V1_
 88         while(1)
 89         {
  90             char buf[1024];
 91             memset(buf,'\0',sizeof(buf));
 92             ssize_t _size=read(new_sock,buf,sizeof(buf)-1);
 93             if(_size<0)
 94             {
 95                 printf("read fail...\n");
 96                 exit(1);
 97             }else if(_size==0)
 98             {
 99                 printf("closed connect...\n");
100                 exit(2);
101             }else
102             {
103                 printf("client# %s",buf);
104             }
105         }
106     }
107 #elif _V2_
108         pid_t id=fork();
109         if(id<0)
110         {
111             printf("create fail...\n");
112             exit(3);
113         }else if(id==0)
114         {
115             close(listen_sock);//close listen_sock,only deal with I/Ostream
116             while(1)
117             {
118                 char buf[1024];
119                 memset(buf,'\0',sizeof(buf));
120                 ssize_t _size=read(new_sock,buf,sizeof(buf)-1);
121                 if(_size<0)
121                 if(_size<0)
122                 {
123                     printf("read fail...\n");
124                     exit(1);
125                 }else if(_size==0)
126                 {
127                     printf("closed connect...\n");
128                     exit(2);
129                 }else
130                 {
131                     printf("client# %s\n",buf);
132                 }
133             }
134             close(new_sock);
135         }else
136         {
137             close(new_sock);
138         }
139     }
140 
141 #elif _V3_
142         pthread_t tid;
143         if(tid=pthread_create(&tid,NULL,thread_run,(void*) new_sock)<0)
144         {
145             perror("pthread_create");
146             exit(2);
147         }
148         pthread_detach(tid);
149     }
150 #else
151     printf("default\n");
152     }
153 #endif 
154    return 0;
155 }


connect函數:

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

向服務器端發送連接請求,只維護一個連接,連接成功後通過sock進行傳輸
客戶端:

1.創建套接字(進行三次握手)

2.向服務器發連接請求

3.傳輸數據

4.關閉套接字(四次揮手,即釋放鏈接)

客戶端代碼:

 1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/socket.h>
  6 #include<netinet/in.h>
  7 #include<arpa/inet.h>
  8 
  9 void usage(char* proc)
 10 {
 11     printf("usage:%s [remoteip] [remoteport]\n",proc);
 12 }
 13 int main(int argc,char*argv[])
 14 {
 15     if(argc!=3)
 16     {
 17         usage(argv[0]);
 18         exit(1);
 19     }
 20     char* remote_ip=argv[1];
 21     int remote_port=atoi(argv[2]);
 22     int sock=socket(AF_INET,SOCK_STREAM,0);
 23     if(sock < 0)
 24     {
 25         perror("socket");
 26         exit(2);
 27     }
 28     struct sockaddr_in remote;
 29     remote.sin_family=AF_INET;
 30     remote.sin_port=htons(remote_port);
 31     remote.sin_addr.s_addr=inet_addr(remote_ip);
 32     //send SYN head
 33     if(connect(sock,(struct sockaddr*)&remote,sizeof(remote))<0)
 34     {
 35         perror("connect");
 36         exit(3);
 37     }
 38     char msg[1024];
 39     while(1)
 40     {
 41         memset(msg,'\0',sizeof(msg));
 42         printf("please input msg:");
 43         fflush(stdout);
 44         if(read(0,msg,sizeof(msg))>0){
 45             write(sock,msg,strlen(msg));
 46         }
 47    
 48     }
 49     return 0;
 50 }


運行結果:

單用戶:

wKioL1dAHu_ScCVyAABP5B4g630041.png



利用線程模擬多用戶:

wKiom1dAHabhO-hTAABgFQiFju8234.png



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章