linux下的TCP小程式
阿新 • • 發佈:2018-12-31
服務端是用多執行緒寫的併發伺服器,比較簡單。
功能:
1. 服務端執行後,即監聽指定的埠。允許多個連線併發執行
2. 服務端接收到客戶端請求後,根據客戶端傳過來的指令完成特定任務:
a) 向客戶端傳送服務端所在機器的當前時間
b) 向客戶端傳送服務端所在機器的名稱
c) 向客戶端傳送當前連線的所有客戶端資訊
d) 其它(向客戶端傳送鍵盤輸入的內容)
3. 客戶端執行後,可以執行以下任務:
a) 連線到指定地址和埠的服務端
b) 斷開與服務端的連線
c) 請求服務端給出當前時間
d) 請求服務端給出其機器的名稱
e) 請求服務端給出當前連線的所有客戶端資訊(編號、IP地址、埠等)
f) 給其他客戶端傳送鍵盤輸入的內容
g) 退出客戶端程式
h) 其它(向伺服器端傳送鍵盤輸入的內容)
客戶端:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <netdb.h> #include <unistd.h> #include <time.h> int main(int argc,char *argv[]) { int connect_fd; int ret; char snd_buf[1024]; int i; int port; int len,lens; static struct sockaddr_in srv_addr; //判斷客戶端執行需要給出具體的連線地址和埠 if(argc!=3) { printf("Usage: %s server_ip_address port\n",argv[0]); return 1; } //獲得輸入的埠 port=atoi(argv[2]); //建立套節字用於客戶端的連線 connect_fd=socket(PF_INET,SOCK_STREAM,0); if(connect_fd<0) { perror("cannot create communication socket"); return 1; } //填充關於伺服器的套節字資訊 memset(&srv_addr,0,sizeof(srv_addr)); srv_addr.sin_family=AF_INET; srv_addr.sin_addr.s_addr=inet_addr(argv[1]); srv_addr.sin_port=htons(port); //連線伺服器,如果連線失敗 ret==-1,結束程式 ret=connect(connect_fd,(struct sockaddr *)&srv_addr,sizeof(srv_addr)); if(ret==-1) { perror("cannot connect to the server"); close(connect_fd); return 1; } memset(snd_buf,0,1024); //成功連線伺服器 while(1) { /* time_t timeval; (void)time(&timeval);*/ lens=strlen(ctime(&timeval)); printf("Please input char:"); fgets(snd_buf,1024,stdin); //鍵盤輸入內容 len = strlen(snd_buf); if(len>0) { write(connect_fd,snd_buf,len);//傳送資訊到伺服器 } len=read(connect_fd,snd_buf,1024);//如果伺服器發來資訊,則讀取,否則等待。。 if(len>0) printf("Message form server(%d): %s\n",len,snd_buf);//列印從伺服器收到的資訊 if(snd_buf[0]=='@')//@為退出字元。 跳出迴圈 break; } close(connect_fd);//斷開與伺服器的連線。 return 0; }
服務端:
#include <pthread.h> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/utsname.h> #include <sys/un.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> #include <netdb.h> #include <time.h> #include <stdlib.h> struct sockaddr_in clt_addr; struct sockaddr_in srv_addr; //執行緒執行函式負責讀寫 void *thr_fn(void *arg) { int size,j,lens; int *parg=(int *)arg; int new_fd=*parg; char recv_buf[1024]; char hostdate[1024]; char snd_buf[1024]; fprintf(stderr,"Server get connection from %s\n",(char* )inet_ntoa(clt_addr.sin_addr));//顯示連線的客戶端ip,並打印出來 printf("new_fd=%d\n",new_fd);//客戶端連線編號 memset(snd_buf,0,1024); time_t timeval; (void)time(&timeval); while((size=read(new_fd,recv_buf,1024))>0)//判斷是否有客戶端傳送資訊過來 { if(recv_buf[0]== '@')//exit break; if(recv_buf[0]== '!')//time { printf("Message from client(%d): %s\n",new_fd,recv_buf); lens=strlen(ctime(&timeval)); write(new_fd,ctime(&timeval),lens); } else if(recv_buf[0]== '#')//host message { char computer[256]; struct utsname uts; if(gethostname(computer,255)!=0||uname(&uts)< 0) { fprintf(stderr, "Coule not get host information\n"); exit(1); } lens=strlen(uts.nodename); char* hostdate=uts.nodename; printf("Message from client(%d): %s\n",new_fd,recv_buf); write(new_fd,hostdate,lens); } else if(recv_buf[0]== '$') { } else { printf("Message from client(%d): %s\n",new_fd,recv_buf); } //伺服器向客戶端發信息 printf("Please input char:"); fgets(snd_buf,1024,stdin); write(new_fd,snd_buf,strlen(snd_buf)); printf("\n"); } close(new_fd); return 0; } int main(int argc,char *argv[]) { socklen_t clt_addr_len; int listen_fd; int com_fd; int ret; int i; static char recv_buf[1024]; static char rev_buf[1024]; int len; int port; pthread_t tid; //判斷客戶端是否填寫埠 if(argc!=2) { printf("Usage:%s port\n",argv[0]); return 1; } //埠的字元轉換 port=atoi(argv[1]); //建立套接字用於伺服器的監聽 listen_fd=socket(PF_INET,SOCK_STREAM,0); if(listen_fd<0) { perror("cannot create listening socket"); return 1; } memset(&srv_addr,0,sizeof(srv_addr)); //填充伺服器資訊 srv_addr.sin_family=AF_INET; srv_addr.sin_addr.s_addr=htonl(INADDR_ANY); srv_addr.sin_port=htons(port); //將伺服器和套節字繫結 ret=bind(listen_fd,(struct sockaddr *)&srv_addr,sizeof(srv_addr)); if(ret==-1) { perror("cannot bind server socket"); close(listen_fd); return 1; } //設定連線5個客戶端 ret=listen(listen_fd,5); if(ret==-1) { perror("cannot listen the client connect request"); close(listen_fd); return 1; } //對每個連線來的客戶端建立一個執行緒,單獨與其進行通訊 ,首先呼叫read函式讀取客戶端傳送來的資訊 while(1) { len=sizeof(clt_addr); com_fd=accept(listen_fd,(struct sockaddr *)&clt_addr,&len); if(com_fd<0) { if(errno==EINTR) { continue; } else { perror("cannot accept client connect request"); close(listen_fd); return 1; } } if((pthread_create(&tid,NULL,thr_fn,&com_fd))==-1)//多執行緒呼叫 ,跳到thr_fn函式 { perror("pthread_create error"); close(listen_fd); close(com_fd); return 1; } } return 0; }