溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

TCP之socket編程

發(fā)布時間:2020-09-13 13:11:00 來源:網(wǎng)絡 閱讀:397 作者:yayaru9240 欄目:網(wǎng)絡安全

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

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

網(wǎng)絡字節(jié)序:網(wǎng)絡數(shù)據(jù)流有大小端之分,發(fā)送主機通常將發(fā)送緩沖區(qū)中的數(shù)據(jù)按內(nèi)存地址從低到高的順序發(fā)出,接收主機把從網(wǎng)絡上接到的字節(jié)依次保存在接收緩沖區(qū)中,也是按內(nèi)存地址從低到高的順序保存,網(wǎng)絡數(shù)據(jù)流的地址規(guī)定:先發(fā)出的數(shù)據(jù)是低地址,后發(fā)出的數(shù)據(jù)是

地址。 

TCP/IP協(xié)議規(guī)定,網(wǎng)絡數(shù)據(jù)流應采用大端字節(jié)序,即低地址高字節(jié)。

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

服務器端socket:

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

2.使用struct socketaddr_in 結(jié)構(gòu)體填充網(wǎng)絡方面信息

3.綁定:將套接字信息填充到內(nèi)核中

4.設置套接字狀態(tài)為監(jiān)聽狀態(tài),接收客戶端發(fā)來的連接請求

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

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

accept函數(shù):在一個套接口接受一個連接。

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

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


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

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

適用于未連接的數(shù)據(jù)報或流類套接口,在connect()listen()調(diào)用前使用。當用socket()創(chuàng)建套接口后,它便存在于一個名字空間(地址族)中,但并未賦名。bind()函數(shù)通過給一個未命名套接口分配一個本地名字來為套接口建立本地捆綁(主機地址/端口號。

服務器端代碼:

 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函數(shù):

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

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

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

2.向服務器發(fā)連接請求

3.傳輸數(shù)據(jù)

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 }


運行結(jié)果:

單用戶:

TCP之socket編程



利用線程模擬多用戶:

TCP之socket編程



向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI