国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

長(zhǎng)春火車站時(shí)刻表分享推廣

長(zhǎng)春火車站時(shí)刻表,分享推廣,用戶注冊(cè)網(wǎng)站開發(fā),寧波網(wǎng)絡(luò)推廣系統(tǒng)在上節(jié)已經(jīng)系統(tǒng)介紹了大致的流程和相關(guān)的API,這節(jié)就開始寫代碼! 回顧上節(jié)的流程: 創(chuàng)建一個(gè)NET文件夾 來存放網(wǎng)絡(luò)編程相關(guān)的代碼: tcp服務(wù)端代碼初步實(shí)現(xiàn)--上 這部分先實(shí)現(xiàn)服務(wù)器的連接部分的代碼并進(jìn)行驗(yàn)證 server1.c&#xff…

在上節(jié)已經(jīng)系統(tǒng)介紹了大致的流程和相關(guān)的API,這節(jié)就開始寫代碼!

回顧上節(jié)的流程:

創(chuàng)建一個(gè)NET文件夾 來存放網(wǎng)絡(luò)編程相關(guān)的代碼:

tcp服務(wù)端代碼初步實(shí)現(xiàn)--上

這部分先實(shí)現(xiàn)服務(wù)器的連接部分的代碼并進(jìn)行驗(yàn)證

server1.c:

#include <sys/types.h>     
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/in.h>
#include <string.h>int main()
{int sockfd;int conn_sockfd;int ret;struct sockaddr_in my_addr;struct sockaddr_in client_addr;memset(&my_addr,0,sizeof(struct sockaddr_in));memset(&client_addr,0,sizeof(struct sockaddr_in));//socketsockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){perror("socket");return 1;}else{printf("socket success, sockfd = %d\n",sockfd);}//bindmy_addr.sin_family = AF_INET;my_addr.sin_port = htons(8888);//host to net (2 bytes)inet_aton("192.168.20.137",&my_addr.sin_addr); //char* format -> net formatret = bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_in));if(ret == -1){perror("bind");return 1;}else{printf("bind success\n");}//listenret = listen(sockfd,10);if(ret == -1){perror("listen");return 1;}else{printf("listening...\n");}//acceptint len = sizeof(struct sockaddr_in);conn_sockfd = accept(sockfd,(struct sockaddr *)&client_addr,&len);if(conn_sockfd == -1){perror("accept");return 1;}else{printf("accept success, client IP = %s\n",inet_ntoa(client_addr.sin_addr));//將網(wǎng)絡(luò)格式的IP地址再轉(zhuǎn)回字符串}//read//write//read//closereturn 0;
}

代碼驗(yàn)證:

先編譯并運(yùn)行這部分代碼:

可見,此時(shí)沒有客戶端進(jìn)行連接,程序會(huì)阻塞在監(jiān)聽的階段

此時(shí)打開windows的cmd(windows系統(tǒng)和linux虛擬機(jī)的系統(tǒng)可以看作兩臺(tái)不同的終端

telnet指令使用的也是TCP協(xié)議

執(zhí)行這條命令后,windows的cmd變成了這樣:

再反觀linux虛擬機(jī):

使用windows的ipconfig可以驗(yàn)證IP地址?:

所以,連接部分的代碼已經(jīng)成功,只是因?yàn)闆]有接下來的數(shù)據(jù)傳輸所以退出了。?

tcp服務(wù)端代碼初步實(shí)現(xiàn)--下

這部分實(shí)現(xiàn)服務(wù)器的連接成功后的讀寫并驗(yàn)證

server1.c:

#include <sys/types.h>     
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/in.h>
#include <string.h>int main()
{int sockfd;int conn_sockfd;int ret;int n_read;int n_write;char readbuf[1024];struct sockaddr_in my_addr;struct sockaddr_in client_addr;memset(&my_addr,0,sizeof(struct sockaddr_in));memset(&client_addr,0,sizeof(struct sockaddr_in));//socketsockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){perror("socket");return 1;}else{printf("socket success, sockfd = %d\n",sockfd);}//bindmy_addr.sin_family = AF_INET;my_addr.sin_port = htons(8888);//host to net (2 bytes)inet_aton("192.168.20.137",&my_addr.sin_addr); //char* format -> net formatret = bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_in));if(ret == -1){perror("bind");return 1;}else{printf("bind success\n");}//listenret = listen(sockfd,10);if(ret == -1){perror("listen");return 1;}else{printf("listening...\n");}//acceptint len = sizeof(struct sockaddr_in);conn_sockfd = accept(sockfd,(struct sockaddr *)&client_addr,&len);if(conn_sockfd == -1){perror("accept");return 1;}else{printf("accept success, client IP = %s\n",inet_ntoa(client_addr.sin_addr));}//readn_read = read(conn_sockfd,&readbuf,1024);if(n_read == -1){perror("read");return 1;}else{printf("%d bytes has been read, context = %s\n",n_read,readbuf);}//writechar *msg = "this is server, I have received your msg\n";n_write = write(conn_sockfd,msg,strlen(msg));if(n_write == -1){perror("write");return 1;}else{printf("%d bytes has been written\n",n_write);}//read//closereturn 0;
}

代碼驗(yàn)證:

這部分如果用windows的telnet,打一個(gè)符號(hào)就會(huì)直接結(jié)束,所以用Linux另開一個(gè)cmd使用telnet來模擬服務(wù)器和客戶端的對(duì)話:

還是先運(yùn)行代碼:

然后運(yùn)行telnet:

反觀服務(wù)端:

?

在連接成功后客戶端輸入一句話然后回車:

客戶端顯示:

服務(wù)器顯示:

可見,數(shù)據(jù)的交互基本沒什么問題。

至此,構(gòu)建了一個(gè)大致的服務(wù)器代碼框架,可以開始著手編寫客戶端的代碼了。

客戶端代碼初步實(shí)現(xiàn)

client.c:

#include <sys/types.h>     
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/in.h>
#include <string.h>int main()
{int sockfd;int ret;int n_read;int n_write;char readbuf[1024];struct sockaddr_in server_addr;memset(&server_addr,0,sizeof(struct sockaddr_in));//socketsockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){perror("socket");return 1;}else{printf("socket success, sockfd = %d\n",sockfd);}//connectserver_addr.sin_family = AF_INET;server_addr.sin_port = htons(8888);//host to net (2 bytes)inet_aton("192.168.20.137",&server_addr.sin_addr); ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));if(ret == -1){perror("connect");return 1;}else{printf("connect success!\n");}//writechar *msg = "client: hello\n";n_write = write(sockfd,msg,strlen(msg));if(n_write == -1){perror("write");return 1;}else{printf("%d bytes has been written\n",n_write);}//readn_read = read(sockfd,&readbuf,1024);if(n_read == -1){perror("read");return 1;}else{printf("%d bytes has been read, context = %s\n",n_read,readbuf);}//closereturn 0;
}

代碼驗(yàn)證:

先編譯并允許服務(wù)端:

再編譯并運(yùn)行客戶端:

?回看服務(wù)端:

?

客戶端 & 服務(wù)端 代碼的最終實(shí)現(xiàn)

之前,已經(jīng)大致編寫出了客戶端和服務(wù)端的代碼,但是和本節(jié)開頭的框圖對(duì)比,發(fā)現(xiàn)還差一些,首先,數(shù)據(jù)的發(fā)送和讀取應(yīng)該持續(xù)進(jìn)行,直到收到結(jié)束信號(hào),另外在最后要編寫關(guān)閉套接字,關(guān)閉連接的代碼,且服務(wù)器應(yīng)該可以接受多個(gè)客戶端的數(shù)據(jù),還有一些細(xì)節(jié)的優(yōu)化

回顧之前關(guān)于fork函數(shù)的一節(jié):進(jìn)程的創(chuàng)建_mjmmm的博客-CSDN博客

?所以此處可以使用fork函數(shù)!

小知識(shí)點(diǎn):自動(dòng)對(duì)齊(gg=G)

(參考:linux代碼對(duì)齊快捷鍵和man幫助文檔的使用總結(jié)_陌上花開緩緩歸以的博客-CSDN博客)

在命令模式下(即非“插入”等編輯模式),先輸入gg,這時(shí)候光標(biāo)會(huì)移動(dòng)到第一行第一個(gè)字符,然后按 “=” 號(hào)之后切換成大寫,再按一下G,這時(shí)候光標(biāo)會(huì)移到最后一行的第一個(gè)字符,這時(shí)候就可以看到代碼被排得整整齊齊了!
“gg"將光標(biāo)移動(dòng)到代碼首部,”="表示對(duì)齊指令,"G"表示代碼尾部,所以執(zhí)行"gg=G"后,該文件的所有代碼都將對(duì)齊!

實(shí)現(xiàn)思路

服務(wù)端:

在listen之后,進(jìn)入一個(gè)while(1)循環(huán),并調(diào)用accept阻塞,一旦連接到一個(gè)客戶端,就fork一個(gè)子進(jìn)程來處理數(shù)據(jù),父進(jìn)程則繼續(xù)通過while(1)繼續(xù)調(diào)用accept阻塞等待下一個(gè)客戶端連接。

而子進(jìn)程中再次調(diào)用fork,父進(jìn)程寫一個(gè)while(1)不斷的寫數(shù)據(jù),子進(jìn)程寫一個(gè)while(1)不斷的讀數(shù)據(jù)。

客戶端:

在connect之后進(jìn)行fork,父進(jìn)程寫一個(gè)while(1)不斷的寫數(shù)據(jù),子進(jìn)程寫一個(gè)while(1)不斷的讀數(shù)據(jù)。

如何退出:

我希望的退出方式是客戶端輸入“quit”就會(huì)退出,但是不管是客戶端還是服務(wù)端,為了讀和寫不會(huì)相互阻塞,都在不同的進(jìn)程中的while(1)里,當(dāng)客戶端輸入“quit”之后,只有客戶端的寫端和服務(wù)器的讀端知道,客戶端的讀端和服務(wù)器的寫端并不知情,所以需要使用進(jìn)程間的通訊,此處我使用了FIFO


在客戶端中創(chuàng)建FIFO并在不斷寫數(shù)據(jù)的父進(jìn)程不斷檢測(cè)是否輸入了“quit”如果是就只寫打開fifo,并阻塞等待....一旦等待到了有進(jìn)程只讀打開FIFO,就會(huì)往FIFO寫入“quit”,然后關(guān)閉FIFO;關(guān)閉套接字;收集子進(jìn)程退出狀態(tài);然后退出循環(huán);正常退出。 同時(shí)在不斷讀數(shù)據(jù)的子進(jìn)程不斷非阻塞的只讀打開fifo,并每次都將光標(biāo)移到最開頭,一旦從FIFO讀取到了“quit”,就exit。


但是,不斷讀數(shù)據(jù)的子進(jìn)程會(huì)阻塞讀取服務(wù)器傳來(寫入)的數(shù)據(jù),這就導(dǎo)致,當(dāng)客戶端輸入“quit”之后無法立刻退出,而是要等到服務(wù)器再發(fā)來消息,才能進(jìn)行下一輪的FIFO讀取,才能使得子進(jìn)程收到父進(jìn)程通過FIFO發(fā)來的“quit”并退出。解決辦法就是:在服務(wù)器端中一旦檢測(cè)到客戶端發(fā)來的消息是quit之后,就立刻給客戶端發(fā)送一句話


此時(shí),對(duì)于客戶端來說輸入了“quit”之后會(huì)立刻退出,但是服務(wù)端只有讀端的while可以退出,寫端的while無法退出,此時(shí)就有一個(gè)疑問“我在讀端關(guān)閉了客戶端套接字,照理說寫端應(yīng)該往這個(gè)套接字里寫會(huì)報(bào)錯(cuò),我直接在報(bào)錯(cuò)處理函數(shù)里退出寫端不就行了”,但其實(shí)這是行不通的,因?yàn)槲募枋龇淖饔糜蚰J(rèn)情況下只在進(jìn)程內(nèi)有效,而無法在進(jìn)程之間進(jìn)行傳遞。所以還是需要使用FIFO,且注意,FIFO是進(jìn)程與進(jìn)程間的,客戶端和服務(wù)端本質(zhì)也屬于兩個(gè)進(jìn)程,所以服務(wù)端如果要使用FIFO應(yīng)該在mkfifo函數(shù)中對(duì)于FIFO的名字修改,不要和服務(wù)端的FIFO重名


在服務(wù)器端創(chuàng)建另一個(gè)FIFO并在不斷讀數(shù)據(jù)的子進(jìn)程不斷判斷是否從客戶端收到了“quit”,如果收到了就立刻回復(fù)(寫)一個(gè)“Bye”(也就是為了讓客戶端能立刻退出);只寫打開FIFO,并阻塞等待....一旦等待到了有進(jìn)程只讀打開FIFO,就會(huì)往FIFO寫入“quit”,然后exit。?同時(shí)在不斷寫數(shù)據(jù)的父進(jìn)程不斷非阻塞的只讀打開fifo,并每次都將光標(biāo)移到最開頭,一旦從FIFO讀取到了“quit”,就關(guān)閉FIFO;關(guān)閉客戶端的套接字;收集子進(jìn)程退出狀態(tài);然后退出循環(huán);執(zhí)行fork之后的exit。

程序框圖:

server_final.c:

#include <sys/types.h>     
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/in.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>int main(int argc, char **argv)
{int conn_num = 0;int flag = 0;int sockfd;int conn_sockfd;int ret;int n_read;int n_write;int len = sizeof(struct sockaddr_in);char readbuf[128];char msg[128];int fd; //fifochar fifo_readbuf[20] = {0};char *fifo_msg = "quit";pid_t fork_return;pid_t fork_return_1;struct sockaddr_in my_addr;struct sockaddr_in client_addr;memset(&my_addr,0,sizeof(struct sockaddr_in));memset(&client_addr,0,sizeof(struct sockaddr_in));if(argc != 3){printf("param error!\n");return 1;}//socketsockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){perror("socket");return 1;}else{printf("socket success, sockfd = %d\n",sockfd);}//bindmy_addr.sin_family = AF_INET;my_addr.sin_port = htons(atoi(argv[2]));//host to net (2 bytes)inet_aton(argv[1],&my_addr.sin_addr); //char* format -> net formatret = bind(sockfd, (struct sockaddr *)&my_addr, len);if(ret == -1){perror("bind");return 1;}else{printf("bind success\n");}//listenret = listen(sockfd,10);if(ret == -1){perror("listen");return 1;}else{printf("listening...\n");}//fifoif(mkfifo("./fifo1",S_IRWXU) == -1 && errno != EEXIST){perror("fifo");}while(1){//acceptconn_sockfd = accept(sockfd,(struct sockaddr *)&client_addr,&len);if(conn_sockfd == -1){perror("accept");return 1;}else{conn_num++;if(conn_num > 1){printf("there are more then one client, msg may not be sent accuratly!\n");}printf("accept success, no.%d client IP = %s\n",conn_num,inet_ntoa(client_addr.sin_addr));}fork_return = fork();if(fork_return > 0){//father keeps waiting for new request//wait(NULL); //cant wait,will block	}else if(fork_return < 0){perror("fork");return 1;}else{//son deals with requestfork_return_1 = fork();if(fork_return_1 > 0){//father keeps writing msgwhile(1){fd = open("./fifo1",O_RDONLY|O_NONBLOCK);lseek(fd, 0, SEEK_SET);read(fd,&fifo_readbuf,20);//printf("read from fifo:%s\n",fifo_readbuf);if(fifo_readbuf[0]=='q' && fifo_readbuf[1]=='u' && fifo_readbuf[2]=='i' && fifo_readbuf[3]=='t'){printf("sorry,the last msg sent fail,client has quit\n");close(fd);close(conn_sockfd);wait(NULL);break;}//writememset(&msg,0,sizeof(msg));//printf("\ntype msg:");scanf("%s",(char *)msg);n_write = write(conn_sockfd,&msg,strlen(msg));if(n_write == -1){perror("write");return 1;}else{printf("%d bytes msg sent\n",n_write);}}}else if(fork_return_1 < 0){perror("fork");return 1;}else{//son keeps reading msgwhile(1){//readmemset(&readbuf,0,sizeof(readbuf));n_read = read(conn_sockfd,&readbuf,128);if(readbuf[0]=='q' && readbuf[1]=='u' && readbuf[2]=='i' && readbuf[3]=='t'){printf("client quit\n");conn_num--;printf("%d client remain\n",conn_num);write(conn_sockfd,"BYE",3);fd = open("./fifo1",O_WRONLY);write(fd,fifo_msg,strlen(fifo_msg));exit(1);}if(n_read == -1){perror("read");return 1;}else{printf("\nclient: %s\n",readbuf);}}}exit(2);}}return 0;
}

client_final.c:

#include <sys/types.h>     
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/in.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>int main(int argc, char **argv)
{int sockfd;int ret;int n_read;int n_write;char readbuf[128];char msg[128];int fd; //fifochar fifo_readbuf[20] = {0};char *fifo_msg = "quit";pid_t fork_return;if(argc != 3){printf("param error!\n");return 1;}struct sockaddr_in server_addr;memset(&server_addr,0,sizeof(struct sockaddr_in));//socketsockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){perror("socket");return 1;}else{printf("socket success, sockfd = %d\n",sockfd);}//connectserver_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[2]));//host to net (2 bytes)inet_aton(argv[1],&server_addr.sin_addr); ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));if(ret == -1){perror("connect");return 1;}else{printf("connect success!\n");}//fifoif(mkfifo("./fifo",S_IRWXU) == -1 && errno != EEXIST){perror("fifo");}//forkfork_return = fork();if(fork_return > 0){//father keeps writing msgwhile(1){//writememset(&msg,0,sizeof(msg));//printf("\ntype msg:");scanf("%s",(char *)msg);n_write = write(sockfd,&msg,strlen(msg));if(msg[0]=='q' && msg[1]=='u' && msg[2]=='i' && msg[3]=='t'){printf("quit detected!\n");fd = open("./fifo",O_WRONLY);write(fd,fifo_msg,strlen(fifo_msg));close(fd);close(sockfd);wait(NULL);break;}if(n_write == -1){perror("write");return 1;}else{printf("%d bytes msg sent\n",n_write);}}}else if(fork_return < 0){perror("fork");return 1;}else{//son keeps reading while(1){fd = open("./fifo",O_RDONLY|O_NONBLOCK);lseek(fd, 0, SEEK_SET);read(fd,&fifo_readbuf,20);//printf("read from fifo:%s\n",fifo_readbuf);if(fifo_readbuf[0]=='q' && fifo_readbuf[1]=='u' && fifo_readbuf[2]=='i' && fifo_readbuf[3]=='t'){exit(1);}//readmemset(&readbuf,0,sizeof(readbuf));n_read = read(sockfd,&readbuf,128);if(n_read == -1){perror("read");return 1;}else{printf("\nserver: %s\n",readbuf);}}}return 0;
}

實(shí)現(xiàn)效果:

編譯并運(yùn)行server端:

編譯并運(yùn)行client端:

此時(shí)回看server端:

?

此時(shí),就可以實(shí)現(xiàn)雙方聊天的功能了:(服務(wù)器左,客戶端右)

為什么不打成hows it?going而是hows/it/going,原因是scanf函數(shù),如果占位符是“%s”即字符串時(shí),空格和換行鍵都會(huì)被視為結(jié)束符號(hào)!

(詳見:scanf與空格_scanf讀空格_CSU迦葉的博客-CSDN博客

所以如果輸入hows it going的話:

解決方法是使用fgets函數(shù)

(詳見:如何讀取帶空格的字符串?

直到客戶端打出“quit” :

客戶端會(huì)立刻退出,服務(wù)器此時(shí)只有讀端知道客戶端退出了

必須再打一句話讓服務(wù)器寫端刷新,這樣才能從FIFO讀取到信息,讓寫端也知道客戶端退出了:

此時(shí),服務(wù)器的讀寫端也全部退出,再次進(jìn)入阻塞狀態(tài),等待新連接...

下面模擬如果同時(shí)有兩個(gè)或以上連接的時(shí)候:(左側(cè)一個(gè)服務(wù)器,右側(cè)兩個(gè)客戶端)?

?我代碼執(zhí)行的順序是:連接第一個(gè)客戶端(右上)--> 服務(wù)器發(fā)送“hi”?-->?連接第二個(gè)客戶端(右下)--> 服務(wù)器發(fā)送“hihi”?--> 服務(wù)器發(fā)送“hihihi”?--> 服務(wù)器發(fā)送“hihihihi”?

可見,連接第一個(gè)客戶端的時(shí)候,服務(wù)器發(fā)送hi準(zhǔn)確的到了右上的客戶端1,但是當(dāng)連接第二個(gè)客戶端了之后,服務(wù)器分別發(fā)送了“hihi”,“hihihi” ,“hihihihi” ,從服務(wù)端看沒有任何區(qū)別,但實(shí)際情況下“hihi”和“hihihihi”到了客戶端1,“hihihi”到了客戶端2,明顯出現(xiàn)了混亂,所以我在代碼中設(shè)置了提醒,檢測(cè)到大于1個(gè)客戶端接入時(shí)會(huì)提醒。

問題探討 和 一些思路過程

  • 如剛剛所說,服務(wù)器用了兩次fork,相當(dāng)于有3個(gè)獨(dú)立的進(jìn)程,所以我的conn_num變量的設(shè)置實(shí)際上是相當(dāng)殘疾的,因?yàn)槲野裞onn_num-- 放在了一個(gè)子進(jìn)程里,而fork之后的變量空間都是獨(dú)立的,所以我的conn_num變量只要有客戶端推出就不準(zhǔn)了,應(yīng)該也使用進(jìn)程間通信來通知,但是鑒于我的代碼實(shí)現(xiàn)目的本來就是雙人聊天,所以多客戶端的連接部分就沒有深入修改了
  • 在我目前的代碼邏輯中,我本來覺得只設(shè)置了一個(gè)conn_sockfd變量來存放客戶端的套接字不合理,因?yàn)楫?dāng)多個(gè)客戶端接入的時(shí)候,套接字可能會(huì)被覆蓋,導(dǎo)致讀寫異常,但是其實(shí)一個(gè)就夠了,原因也是因?yàn)閒ork之后變量空間也會(huì)被復(fù)制,根據(jù)我的代碼邏輯,每出現(xiàn)一個(gè)新連接,就會(huì)fork一個(gè)子進(jìn)程來處理這個(gè)連接的讀寫,如果有多個(gè)客戶端,就會(huì)有多個(gè)子進(jìn)程,里面的套接字變量名都是conn_sockfd,但其實(shí)值是不一樣的。
  • 并且,服務(wù)端的第一個(gè)fork,父進(jìn)程不能調(diào)用wait,因?yàn)閣ait會(huì)阻塞直到子進(jìn)程退出,但我希望父進(jìn)程不被阻塞而一直while循環(huán)等待新連接,所以第一次fork生成的子進(jìn)程在客戶端退出之后會(huì)變成僵尸進(jìn)程,且每有一個(gè)新的客戶端退出就會(huì)多一個(gè)僵尸進(jìn)程,在當(dāng)前的邏輯下不可避免。

且,當(dāng)多個(gè)客戶端連接服務(wù)器的時(shí)候,服務(wù)器會(huì)針對(duì)每個(gè)客戶端fork一個(gè)子進(jìn)程來處理,而每一個(gè)子進(jìn)程都會(huì)再fork一個(gè)讀端不停的scanf檢測(cè)輸入

但是進(jìn)程與進(jìn)程之間是競(jìng)爭(zhēng)的關(guān)系,所以在cmd中看來,光標(biāo)一直在閃沒有變化,但實(shí)際上,可能上一秒這是客戶端1對(duì)應(yīng)子進(jìn)程的scanf,下一秒就變成了客戶端2對(duì)應(yīng)子進(jìn)程的scanf。

這就導(dǎo)致了如果此時(shí)對(duì)著光標(biāo)輸入消息并回車,無法確定收到消息的是客戶端1還是客戶端2。

  • 解決辦法1:使用線程,實(shí)現(xiàn)真正的多方數(shù)據(jù)收發(fā),但是難度很大,需要更多的新知識(shí)
  • 解決辦法2:舍棄服務(wù)器的scanf功能,改為自動(dòng)回復(fù),這樣可以實(shí)現(xiàn)多個(gè)客戶端對(duì)服務(wù)器的自定義消息發(fā)送,但是服務(wù)器只能回復(fù)預(yù)設(shè)的內(nèi)容
  • 解決辦法3:(也就是現(xiàn)在實(shí)現(xiàn)的效果)舍棄多方發(fā)送,只用一個(gè)客戶端,這樣就可以實(shí)現(xiàn)客戶端和服務(wù)器的自定義消息交互,但是此時(shí)不能增加更多的客戶端
http://aloenet.com.cn/news/47999.html

相關(guān)文章:

  • 邯鄲有學(xué)做搭建網(wǎng)站的嗎seo網(wǎng)站搜索優(yōu)化
  • 鑫菲互動(dòng)網(wǎng)站建設(shè)公司愛站seo查詢
  • 閥門網(wǎng)站建設(shè)國(guó)色天香站長(zhǎng)工具
  • 網(wǎng)站底部圖片突發(fā)大事震驚全國(guó)
  • 做網(wǎng)站外快一年的百度指數(shù)
  • 昆明做網(wǎng)站競(jìng)價(jià)品牌推廣策劃
  • 如何通過做威客賺錢長(zhǎng)春網(wǎng)站優(yōu)化方案
  • 網(wǎng)站建設(shè)阿膠膏的作用優(yōu)化推廣網(wǎng)站淄博
  • 天津注冊(cè)公司網(wǎng)站宣傳網(wǎng)站怎么做
  • 做seo網(wǎng)站的公司媒體邀約
  • 建設(shè)好網(wǎng)站靠什么賺錢適合40歲女人的培訓(xùn)班
  • 貴陽網(wǎng)站建設(shè)黔搜seo顧問是什么職業(yè)
  • 做網(wǎng)站要有策劃么人工智能培訓(xùn)師
  • 銀川網(wǎng)站建設(shè)廣告公司百度seo優(yōu)化方法
  • php動(dòng)態(tài)網(wǎng)站開發(fā)考試題河南專業(yè)網(wǎng)絡(luò)推廣公司
  • 北京網(wǎng)站案例谷歌廣告投放
  • 安陽做網(wǎng)站的公司宣傳軟文是什么
  • 做網(wǎng)站銷售 優(yōu)幫云不受國(guó)內(nèi)限制的瀏覽器
  • wordpress網(wǎng)頁怎么上傳到服務(wù)器錯(cuò)誤上海高玩seo
  • 展示網(wǎng)站欣賞百度怎么注冊(cè)公司網(wǎng)站
  • 在門戶網(wǎng)站上做推廣百度瀏覽器官網(wǎng)在線使用
  • 免費(fèi)空間使用指南抖音搜索排名優(yōu)化
  • 實(shí)時(shí)爬蟲網(wǎng)站是怎么做的蘇州網(wǎng)站seo服務(wù)
  • 自貢訂房中心網(wǎng)站建設(shè)aso優(yōu)化是什么
  • 怎么建站網(wǎng)站百度愛采購關(guān)鍵詞優(yōu)化
  • 網(wǎng)站建設(shè)1選宙斯站長(zhǎng)東莞疫情最新消息今天新增
  • 怎么在word上做超鏈接網(wǎng)站2345網(wǎng)址導(dǎo)航下載桌面
  • 芷江建設(shè)工程招投標(biāo)網(wǎng)站b2b和b2c是什么意思
  • 網(wǎng)站做關(guān)鍵詞排名有必要嗎企業(yè)郵箱入口
  • 便宜虛擬主機(jī)做網(wǎng)站備份搜索引擎營(yíng)銷是指