摘要:分為兩個獨立的程序編譯前先確定自己服務器的地址,比如想要在自己的下運行,先獲取自己的地址,修改,里面的地址為自己的地址服務端編譯運行客戶端編譯運行服務端先運行起來后,再啟動客戶端,可以在多態機器上啟多個客戶端,互相聊天
分為兩個獨立的程序
編譯前先確定自己服務器的地址,比如想要在自己的ubuntu下運行,先ip addr獲取自己的ip地址,修改chat_server.c,chat_client.c里面的ip地址為自己的ip地址
服務端chat_server.c
編譯: gcc chat_server.c -o server
運行: ./server
#include#include #include #include #include #include #include #include #include #define MAX_USER 500 #define MAX_MSG_LEN 1024 #define MAX_IO_RETRY_TIMES 5 int server_fd; int user_cnt = 0; int user_fds[MAX_USER]; char msg_buffer[MAX_MSG_LEN]; void down() { int i; for(i = 0; i < user_cnt; i++) { shutdown(user_fds[i], SHUT_RDWR); close(user_fds[i]); user_fds[i] = 0; } shutdown(server_fd, SHUT_RDWR); close(server_fd); server_fd = 0; } int go_on = 1; void sig_handler(int signal) { go_on = 0; } int my_safe_read(int fd) { int ret; int i; for(i = 0; i < MAX_IO_RETRY_TIMES; i++) { errno = 0; int ret = read(fd, msg_buffer, MAX_MSG_LEN); if(ret < 0) { if(EAGAIN == errno || EWOULDBLOCK == errno) { printf("Safe read [%d] cnt ", i + 1); continue; } else { return ret; } } else if(0 == ret) { return 0; } else { return ret; } } return ret; } int my_safe_write(int fd) { write(fd, msg_buffer, MAX_MSG_LEN); } int main(int argc, char *argv[]) { signal(SIGINT, sig_handler); server_fd = socket(AF_INET, SOCK_STREAM, 0); if(-1 == server_fd) { printf("socket err "); return -1; } printf("socket ok "); struct sockaddr_in server_addr; bzero(&server_addr, sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); unsigned short portnum = 0x8888; if(argc >= 2) { int port = atoi(argv[1]); if(port > 20000) { portnum = port; } } printf("port = %d ", portnum); server_addr.sin_port = portnum; if(-1 == bind(server_fd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr))) { printf("bind err "); return -1; } printf("bind ok "); if(-1 == listen(server_fd, MAX_USER)) { printf("listen err "); return -1; } printf("listen ok "); int i; fd_set fds; struct timeval tv; while(go_on) { FD_ZERO(&fds); FD_SET(server_fd, &fds); for(i = 0; i < user_cnt; i++) { printf("-%d ", user_fds[i]); if(user_fds[i]) { FD_SET(user_fds[i], &fds); } } int fd_cnt_to_selected = 0; for(i = 0; i < user_cnt; i++) { if(user_fds[i] > fd_cnt_to_selected) { fd_cnt_to_selected = user_fds[i]; } } fd_cnt_to_selected = (0 == user_cnt)? (server_fd + 1) : (fd_cnt_to_selected + 1); tv.tv_sec = 2; tv.tv_usec = 0; int ret = select(fd_cnt_to_selected, &fds, 0, 0, &tv); if(ret < 0) { printf("select err "); break; } else if(0 == ret) { continue; } struct sockaddr_in client_addr; for(i = 0; i < user_cnt; i++) { if(FD_ISSET(user_fds[i], &fds)) { bzero(msg_buffer, MAX_MSG_LEN); int ret = my_safe_read(user_fds[i]); if(ret <= 0) { int connection_state = 1; int len_of_int = sizeof(int); getsockopt(user_fds[i], IPPROTO_TCP, SO_KEEPALIVE, (void*)&connection_state, &len_of_int); printf("connection_state = %s ", (0 == connection_state)? "break" : "alive"); if(0 == connection_state) { close(user_fds[i]); FD_CLR(user_fds[i], &fds); if(user_cnt - 1 == i) { user_cnt = user_cnt - 1; user_fds[i] = 0; } else { int j; for(j = i; j < user_cnt; j++) { user_fds[j] = user_fds[j+1]; } user_fds[j] = 0; user_cnt = user_cnt -1; } } } else { printf("receive[%s] ", msg_buffer); int j; for(j = 0; j < user_cnt; j++) { if(j == i) { continue; } my_safe_write(user_fds[j]); } } } } if(FD_ISSET(server_fd, &fds)) { int sin_size = sizeof(struct sockaddr); user_fds[user_cnt] = accept(server_fd, (struct sockaddr *)(&client_addr), &sin_size); if(-1 == user_fds[user_cnt]) { printf("accept err "); return -1; } printf("accept ok! "); printf("user_fds[user_cnt] = %d ", user_fds[user_cnt]); user_cnt++; } } down(); return 0; }
客戶端chat_client.c
編譯: gcc chat_client -lpthread -o chat_client
運行: 服務端先運行起來后,再啟動客戶端,可以在多態機器上啟多個客戶端,互相聊天
./chat_client
#include#include #include #include #include #include #include #include #include #include int cfd = 0; struct passwd *pwd; void sig_handler(int signal) { char bye_msg[1024] = { 0 }; sprintf(bye_msg, "WARNING------>User[%s] have go, he said all is "SB"! Oh, what the fuck!", pwd->pw_name); write(cfd, bye_msg, 1024); shutdown(cfd, SHUT_RDWR); close(cfd); cfd = 0; exit(-1); } void* f(void* t) { struct timeval tv; fd_set fds; while(1) { tv.tv_sec = 0; tv.tv_usec = 100; FD_ZERO(&fds); FD_SET(cfd, &fds); int r = select(cfd + 1, &fds, 0, 0, &tv); if(r<0) { printf("select err "); } else if(r==0) { } char buf[1024*10] = { 0 }; int n = read(cfd, buf, 1024*10); if(buf[0] != 0) printf("%s ", buf); } } int main(int argc, char * argv[]) { signal(SIGINT, sig_handler); pwd = getpwuid(getuid()); int recbytes; int sin_size; char buffer[1024] ={0}; struct sockaddr_in s_add, c_add; unsigned short portnum =0x8888; if(argc >= 2) { int port = atoi(argv[1]); if(port > 20000) portnum = port; } printf("port = %d ", portnum); cfd = socket(AF_INET, SOCK_STREAM, 0); if(-1 == cfd) { printf("socket err "); return -1; } //printf("socket ok "); bzero(&s_add, sizeof(struct sockaddr_in)); s_add.sin_family = AF_INET; s_add.sin_addr.s_addr = inet_addr("192.168.60.104"); s_add.sin_port = htons(portnum); if(-1 == connect(cfd, (struct sockaddr *)(&s_add), sizeof(struct sockaddr))) { printf("connect err "); return -1; } char personal_info[128] = { 0 }; sprintf(personal_info, "DouBi[%s] is comming!!!HaHaaa^-^", pwd->pw_name); write(cfd, personal_info, 128); //printf("connect ok "); pthread_t th; int rr = pthread_create((pthread_t *)&th, NULL, f, NULL); while(1) { //printf("enter what you want to say:_ "); char b[10240] = { 0 }; sprintf(b, "[%s]: ", pwd->pw_name); gets(b + strlen(b)); //printf("b = %s ", b); if(-1 == (recbytes = write(cfd, b, 1024*10))) { printf("send data err "); return -1; } //printf("send ok "); } //close(cfd); // sleep(100); return 0; }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/25004.html
摘要:用偽代碼來模擬下長輪詢的過程前端利用下面函數進行請求后端代碼做如下更改利用隨機數的大小來模擬是否有新數據有新數據來了長輪詢的確減少了請求的次數,但是它也有著很大的問題,那就是耗費服務器的資源。 寫在前面 最近由于利用node重構某個項目,項目中有一個實時聊天的功能,于是就研究了一下聊天室,在線demo|源碼,歡迎大家反饋。這個聊天室的主要利用到了socket.io和express。這個...
摘要:簡易版聊天室技術棧功能實現實時聊天創建房間表情包完善私聊效果登錄服務端判斷之前是否登錄過聊天室,如果是則直接進入聊天室,否則跳轉到登錄頁面??蛻舳税l送創建房間和切換房間的事件給服務端。 Chat 簡易版聊天室 技術棧 express socket.io 功能 實現 實時聊天 創建房間 表情包 完善 私聊 效果 登錄 showImg(https://segmentfa...
摘要:下文如無特殊聲明將使用進程同時表示進程線程。收到數據后服務器程序進行處理然后使用向客戶端發送響應?,F在各種高并發異步的服務器程序都是基于實現的,比如。 并發 IO 問題一直是服務器端編程中的技術難題,從最早的同步阻塞直接 Fork 進程,到 Worker 進程池/線程池,到現在的異步IO、協程。PHP 程序員因為有強大的 LAMP 框架,對這類底層方面的知識知之甚少,本文目的就是詳細介...
閱讀 3196·2021-11-18 10:02
閱讀 1446·2021-10-12 10:08
閱讀 1236·2021-10-11 10:58
閱讀 1269·2021-10-11 10:57
閱讀 1167·2021-10-08 10:04
閱讀 2121·2021-09-29 09:35
閱讀 773·2021-09-22 15:44
閱讀 1269·2021-09-03 10:30