Linux TCP程式設計常見問題考慮
原始碼:tcp_server.c
int main(void) { struct sockaddr_in servaddr, cliaddr; socklen_t cliaddr_len; int listenfd, clifd; char str[INET_ADDRSTRLEN]; char buf[MAXBYTES]; int i, n, len; listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERVER_PORT); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, 128); printf("Accepting connections ...\n"); while (1) { bzero(&buf, sizeof(buf)); cliaddr_len = sizeof(cliaddr); clifd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); if(clifd == -1) { perror("clifd"); continue; } len = read(clifd, buf, sizeof(buf) - 1); if(len != -1) { printf("accept from %s at PORT %d :[%d] %s\n" , inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)) , ntohs(cliaddr.sin_port), len, buf); } else { perror("read"); } close(clifd); } return 0;
測試伺服器是否好用可以使用一下命令:
nc 127.0.0.1 8888
2 搭建一個TCP客戶端
原始碼:tcp_client.c
int main(int argc, char *argv[]) { struct sockaddr_in serveraddr; int sockfd, n, ret; char buf[] = "helloworld"; sockfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr); serveraddr.sin_port = htons(SERVER_PORT); ret = connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); if(ret == -1) perror("connect"); ret = write(sockfd, buf, strlen(buf)); if(ret == -1) perror("connect"); close(sockfd); return 0; }
需要注意的事:
1.當socket寫端關閉的時候,讀端read將一直讀取到0位元組,可以使用這一特性來關閉讀端套接字。
2.當socket讀端關閉的時候,寫端write繼續寫入資料,將會報錯,並且收到一個SIGPIPE訊號。
3.當網路異常的時候(如拔掉網線),這個時候read不會返回錯誤,將阻塞等待資料;write也不會返回錯誤,仍然可以寫入資料,直到寫buffer填滿,將阻塞write函式。
4.socket有個buffer,並且這個buffer的大小是一定的,當一直往socket write的時候,達到這個buffer的最大值後,write將阻塞。
伺服器改寫如下:
int main(void) { struct sockaddr_in servaddr, cliaddr; socklen_t cliaddr_len; int listenfd, clifd; char str[INET_ADDRSTRLEN]; char buf[MAXBYTES]; int i, n, len; listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERVER_PORT); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, 128); printf("Accepting connections ...\n"); while (1) { bzero(&buf, sizeof(buf)); cliaddr_len = sizeof(cliaddr); clifd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); //可能被訊號中斷需要注意 if(clifd == -1) { perror("read"); return -1; } while(1) { len = read(clifd, buf, sizeof(buf) - 1); if(len > 0) { printf("accept from %s at PORT %d :[%d] %s\n" , inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)) , ntohs(cliaddr.sin_port), len, buf); } else if(len == 0) //寫端關閉的時候將永遠讀到0位元組,如果讀到0位元組就可以關閉套接字了 { close(clifd); break; } else { perror("read"); } sleep(1); } } close(listenfd); return 0; }
客戶端改寫如下:
void sig_handler(int sig) { printf("SIGPIPE\n"); } int main(int argc, char *argv[]) { signal(SIGPIPE, sig_handler); //當讀端關閉的時候,如果繼續寫,則會觸發SIGPIPE訊號 struct sockaddr_in serveraddr; int sockfd, n, ret; char buf[] = "helloworld"; sockfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr); serveraddr.sin_port = htons(SERVER_PORT); int conntimes = 0; while(connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1) //有可能連結失敗,通過這種方式定時連結 { if(conntimes++ > 10) return -1; sleep(1); perror("connect"); } int num = 0; while(1) { ret = write(sockfd, buf, strlen(buf)); if(ret == -1) { perror("write"); } else num += ret; printf("send bytes %d\n", num); sleep(1); //該值根據需要進行更改。 } close(sockfd); return 0; }
相關文章
- TCP常見問題總結TCP
- Python程式設計常見問題與解答Python程式設計
- Linux網路程式設計常見面試題Linux程式設計面試題
- Java程式設計師面試常見問題Java程式設計師面試
- Linux 常見問題Linux
- 畢業設計常見問題
- 網頁設計常見問題網頁
- 好程式設計師分享:Java面試題常見問題程式設計師Java面試題
- Python爬蟲程式設計常見問題解決方法Python爬蟲程式設計
- 【Linux網路程式設計】網路程式設計常見概念Linux程式設計
- Python教程之網路程式設計及前端常見問題!Python程式設計前端
- SOLIDWORKS認證考試常見問題解答Solid
- 好程式設計師雲端計算教程分享Linux雲端計算面試常見問題一程式設計師Linux面試
- 好程式設計師雲端計算教程分享Linux雲端計算面試常見問題二程式設計師Linux面試
- 好程式設計師雲端計算教程分享Linux雲端計算面試常見問題三程式設計師Linux面試
- 好程式設計師Python教程分享Python常見面試問題程式設計師Python面試
- 5年程式設計師面試,常見面試問題解析程式設計師面試
- CodeReview常見程式碼問題View
- MaxCompute計費常見問題
- 好程式設計師大資料培訓之Hadoop常見問題程式設計師大資料Hadoop
- 低程式碼專案建設常見問題解析
- Linux 常見問題 - 拒絕遠端訪問Linux
- 面對海量請求,快取設計還應該考慮哪些問題?快取
- socket程式設計中常見的概念問題!程式設計
- 常見問題
- 好程式設計師大資料培訓簡述Hadoop常見問題程式設計師大資料Hadoop
- 四個常見的Linux面試問題Linux面試
- Marvelous Designer 服裝設計(遊戲向) 常見問題遊戲
- 遊戲策劃設計系統時,除了考慮設計目的,還需要考慮什麼?遊戲
- TCP協議的常見面試題TCP協議面試題
- 好程式設計師web前端培訓分享小白學web常見的問題程式設計師Web前端
- 雲端計算面試常見問題:Linux目錄結構面試Linux
- 好程式設計師web前端分享常見面試題程式設計師Web前端面試題
- 程式設計師需要重新考慮無程式碼開發的原因。程式設計師
- js常見問題JS
- Homestead 常見問題
- Apache 常見問題Apache
- Git 常見問題Git
- PHP 常見問題PHP