您好,登錄后才能下訂單哦!
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é)果:
單用戶:
利用線程模擬多用戶:
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。