TCP客戶端服務器編程模型:html
服務器:編程
客戶端:服務器
Linux下和Mac下代碼同樣的,可能有頭文件不太同樣,用man命令進去查看便可。網絡
功能:多線程
服務器代碼 time_tcp_server.c:併發
#include <sys/socket.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <time.h> #include <string.h> #include <netdb.h> #include <arpa/inet.h> #define SERVER_PORT 8888 #define LISTEN_QUEUE_SISE 10 int socketfd; void signal_handler(int signo) { printf("this serveice close\n"); close(socketfd); exit(1); } void out_clientinfo(const struct sockaddr_in* outsockaddr) { char ipstr[16]; memset(ipstr, 0, sizeof(ipstr)); // 將地址從網絡字節序轉換爲點分十進制 inet_ntop(AF_INET, &outsockaddr->sin_addr.s_addr, ipstr, sizeof(ipstr)); printf("Connected by %s(%d)\n", ipstr, ntohs(outsockaddr->sin_port)); } void dosomething(int fd) { //獲取系統當前時間 long t = time(0); char* times = ctime(&t); size_t size = strlen(times)*sizeof(char); //將時間寫回到客戶端 if(write(fd, times, size) != size) { perror("write to client error"); } } int main(int argc, char const *argv[]) { if (signal(SIGINT, signal_handler) == SIG_ERR) { perror("signal error"); exit(1); } // 1 sokect // AF_INET ipv4 // SOCK_STREAM tcp if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket error"); exit(1); } // 2 bind 綁定本地地址和端口 struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET;//ipv4 serveraddr.sin_port = htons(SERVER_PORT); //端口 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);//響應任意網卡的請求 if(bind(socketfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) { perror("bind error"); exit(1); } // 3 listen 啓動監聽 通知系統接受來自客戶端的鏈接 準備好鏈接隊列 if(listen(socketfd, LISTEN_QUEUE_SISE) < 0) { perror("listen error"); exit(1); } struct sockaddr_in clientaddr; socklen_t clientaddr_len = sizeof(clientaddr); while(1) { // 4 accept 從隊列拿出第一個 // clientaddr獲取客戶端的地址信息,是傳出參數 int clientfd = accept(socketfd, (struct sockaddr*)&clientaddr, &clientaddr_len); if (clientfd < 0) { perror("accept error"); continue; } // 5 read/write out_clientinfo(&clientaddr); dosomething(clientfd); // 6 close close(clientfd); } // 6 close return 0; }
客戶端代碼time_tcp_client:socket
#include <sys/socket.h> #include <stdlib.h> #include <sys/types.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <netdb.h> #define SERVER_PORT 8888 #define SERVER_IP 127.0.0.1 int main(int argc, char const *argv[]) { //1 建立socket int socketfd = socket(AF_INET, SOCK_STREAM, 0); if (socketfd < 0) { perror("socket error"); exit(1); } //2 connect struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(SERVER_PORT); if(connect(socketfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0 ) { perror("connect error"); exit(1); } //3 read write char buf[1024];
//read是阻塞函數 若是服務器沒有下發消息,會一直阻塞在這裏,知道收到消息。 if (read(socketfd, buf, sizeof(buf)) > 0) { printf("%s",buf); } //4 close close(socketfd); return 0; }
本例只是簡單的處理,服務器返回客戶端一個時間,而後關閉了socket。tcp
若是要進行雙向通訊,服務器勢必要調用read函數,而read默認阻塞,那麼若是客戶端不向服務器發送數據,則主線程一直阻塞,其它客戶端沒法鏈接成功。這就須要處理高併發問題。函數
服務器高併發處理的三種方式高併發