開發環境:Linux,GCC
相關知識:TCP(博客:傳送門),線程
附加:項目可能還有寫不足之處,有些bug沒調出來(如:對在線人數的控制),希望大佬賜教。
那么話不多說,放碼過來:
服務端:server.c
#include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <pthread.h> struct sockaddr_in addr = {}; int clifd_index = 0; // clifd的下標 char buf[1024] = {}; // 存儲客戶端發來的字符串 char str[1024] = {}; // 存儲帶clifd的回傳信息 int clifd[30] = {}; // 存儲clifd int online_num = 0; // 連接人數 int max_num = 10; // 最大人數 // 項目有bug,連接人數的限制控制不住,有待改進 void* start_read(void *arg) // 讀取信息的子線程 { // printf("arg:%d\n",*(int*)arg); int clifd1 = *(int*)arg; printf("run_clifd:%d\n",clifd1); for(;;) { // printf("before read\n"); int ret = read(clifd1,buf,sizeof(buf)); printf("\nip:%s,port:%hu,size:%d\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port),ret); // 獲取相關信息 printf("say:%s\n",buf); char id[10] = {}; sprintf(id,"%d說:",clifd1); if(strlen(buf) != 0) { strcpy(str,id); strcat(str,buf); } // 存入str中 if(0 == strcmp("quit",buf)) // 如果收到quit { online_num--; // 在線人數-1 for(int i=0; i<clifd_index; i++) { if(clifd1 == clifd[i]) { int *die = &clifd1; clifd[i] = 0; pthread_exit(die); // 終止線程 break; } } } //usleep(1000); } } void* start_write(void *arg) // 寫回的子線程 { // printf("arg:%d\n",*(int*)arg); // usleep(500); int clifd1 = *(int*)arg; printf("run_clifd:%d\n",clifd1); for(;;) { int flag = 0; for(int i=0; i<clifd_index; i++) // 因為讀到quit的原因,clifd被置0 { if(clifd1 == clifd[i]) { break; } if(i == clifd_index-1) { int *die = &clifd1; flag = 1; pthread_exit(die); // 終止此寫回的子線程 } } if(flag == 1) { break; } if(strlen(str) == 0) // 空消息不寫入 continue; printf("before write\n"); printf("str:%s\n",str); write(clifd1,str,strlen(str)+1); usleep(50000); // 最快的子線程等待其他子線程 memset(str,0,1024); // 清空str } } int main() { printf("服務器創建socket...\n"); int sockfd = socket(AF_INET,SOCK_STREAM,0); if(0 > sockfd) { perror("socket"); return -1; } printf("准備地址...\n"); addr.sin_family = AF_INET; addr.sin_port = htons(6008);//端口號 addr.sin_addr.s_addr = inet_addr("10.0.2.15");//你的ip地址(或服務器的私網ip) socklen_t len = sizeof(addr); printf("綁定socket與地址...\n"); if(bind(sockfd,(struct sockaddr*)&addr,len)) { perror("bind"); return -1; } printf("設置監聽...\n"); if(listen(sockfd,2)) { perror("listen"); return -1; } printf("等待客戶端連接...\n"); for(;;) { if(online_num < max_num) { struct sockaddr_in addrcli = {}; clifd[clifd_index] = accept(sockfd,(struct sockaddr*)&addrcli,&len); int flag = 0; for(int i=0; i<clifd_index; i++) { if(clifd[clifd_index] == clifd[i]) { flag = 1; break; } } if(flag == 1) { clifd_index--; continue; } else { char link[50] = {}; char link1[40] = "您已經成功連接"; sprintf(link,"您的id是:%d,",clifd[clifd_index]); strcat(link,link1); write(clifd[clifd_index],link,strlen(link)+1); online_num++; } } else { continue; } if(0 > clifd[clifd_index]) { perror("accept"); continue; } printf("clifd:%d\n",clifd[clifd_index]); // 創建子線程 pthread_t pid1,pid2; pthread_create(&pid1,NULL,start_read,&clifd[clifd_index]); pthread_create(&pid2,NULL,start_write,&clifd[clifd_index]); usleep(1000); // printf("clifd:%d\n",clifd[index]); clifd_index++; // 下標逐漸+1,這樣寫不是很合適 } return 0; }

客戶端:client.c
#include <stdio.h> #include <unistd.h> #include <arpa/inet.h> #include <string.h> #include <pthread.h> void* start_read(void* arg) // 讀取信息 { int sockfd = *(int*)arg; char buf[1024] = {}; for(;;) { read(sockfd,buf,sizeof(buf)); if(strlen(buf) != 0) { printf("\n>%s\n",buf); } } } int main() { printf("服務器創建socket...\n"); int sockfd = socket(AF_INET,SOCK_STREAM,0); if(0 > sockfd) { perror("socket"); return -1; } printf("准備地址...\n"); struct sockaddr_in addr = {}; addr.sin_family = AF_INET; addr.sin_port = htons(6008);//設置的端口號 addr.sin_addr.s_addr = inet_addr("10.0.2.15");//你的ip地址(或服務器的公網ip) socklen_t len = sizeof(addr); printf("綁定連接服務器...\n"); if(connect(sockfd,(struct sockaddr*)&addr,len)) { perror("connect"); return -1; } char link[50] = {}; read(sockfd,link,sizeof(link)); // printf("link:%s\n",link); if(strstr(link,"您已經成功連接")==NULL) { printf("連接人數已滿,請稍后重試\n"); return 0; } else { printf("link:%s\n",link); } // 創建讀取子線程 pthread_t pid; pthread_create(&pid,NULL,start_read,&sockfd); for(;;) { char buf[1024] = {}; usleep(1000); //printf(">我說:"); gets(buf); write(sockfd,buf,strlen(buf)+1); if(0 == strcmp("quit",buf)) { printf("通信結束!\n"); break; } } close(sockfd); }