C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易網(wǎng)絡(luò)聊天室
本文實(shí)例為大家分享了C語(yǔ)言實(shí)現(xiàn)網(wǎng)絡(luò)聊天室的具體代碼,供大家參考,具體內(nèi)容如下
業(yè)務(wù)邏輯:
1、客戶端注冊(cè)名字
2、告訴所有在線的客戶端,XXX進(jìn)入聊天室
3、新建一個(gè)線程為該客戶端服務(wù),隨時(shí)接收客戶端發(fā)送來(lái)的消息
4、當(dāng)接收到一個(gè)客戶端的消息時(shí),向每一個(gè)客戶端轉(zhuǎn)發(fā)一份(群聊)
5、同時(shí)在線人數(shù)最多50人
任何客戶端可以隨意隨時(shí)進(jìn)入或退出客戶端
服務(wù)端代碼server.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <pthread.h> #include <semaphore.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #ifndef DEBUG #define debug(format,...) {} #else #define debug(format,...) \ {\ fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\ fprintf(stdout,format,##__VA_ARGS__);\ fprintf(stdout,"\n");\ } #endif//DEBUG #define error(format,...)\ {\ fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\ fprintf(stdout,format,##__VA_ARGS__);\ fprintf(stdout,":%m\n");\ exit(EXIT_FAILURE);\ } // 客戶端最大連接數(shù) #define CLIENT_MAX 50 // 服務(wù)器端口號(hào) #define PORT 5566 // 緩沖區(qū)大小 #define BUF_SIZE 4096 // 重定義socket地址類型 typedef struct sockaddr* SP; // 客戶端結(jié)構(gòu)體 typedef struct Client { int sock;//socket 標(biāo)識(shí)符 pthread_t tid; //線程ID char name[20]; struct sockaddr_in addr; }Client; // 定義50個(gè)存儲(chǔ)客戶端的結(jié)構(gòu)變量 Client clients[50]; // 定義信號(hào)量用于限制客戶端的數(shù)量 sem_t sem; // 信號(hào)處理函數(shù) void sigint(int num) { for(int i=0; i<10; i++) { if(clients[i].sock) { pthread_cancel(clients[i].tid);//銷毀線程 } } debug("服務(wù)器退出!"); exit(EXIT_SUCCESS); } void client_eixt(Client* client) { sem_post(&sem); close(client->sock); client->sock = 0; } void client_send(Client* client,char* buf) { size_t len = strlen(buf)+1; for(int i=0; i<CLIENT_MAX; i++) { if(clients[i].sock && clients[i].sock != client->sock) { send(clients[i].sock,buf,len,0); } } } void* run(void* arg) { Client* client = arg; char buf[BUF_SIZE] = {}; // 接收昵稱 int ret_size = recv(client->sock,client->name,20,0); if(0 >= ret_size) { client_eixt(client); return NULL; } // 通知其它客戶端新人上線 sprintf(buf,"!!!歡迎%s進(jìn)入聊天室!!!",client->name); client_send(client,buf); for(;;) { // 接收消息 ret_size = recv(client->sock,buf,BUF_SIZE,0); if(0 >= ret_size || 0 == strcmp("quit",buf)) { // 通知其它客戶端退出 sprintf(buf,"!!!%s退出聊天室!!!",client->name); client_send(client,buf); client_eixt(client); return NULL; } strcat(buf,":"); strcat(buf,client->name); client_send(client,buf); debug(buf); } } int main(int argc,const char* argv[]) { signal(SIGINT,sigint); debug("注冊(cè)信號(hào)處理函數(shù)成功!"); sem_init(&sem,0,CLIENT_MAX); debug("初始化信號(hào)量成功!"); int svr_sock = socket(AF_INET,SOCK_STREAM,0); if(0 > svr_sock) { error("socket"); } debug("創(chuàng)建socket對(duì)象成功!"); struct sockaddr_in svr_addr = {}; svr_addr.sin_family = AF_INET; svr_addr.sin_port = htons(PORT); svr_addr.sin_addr.s_addr = INADDR_ANY; socklen_t addrlen = sizeof(svr_addr); debug("準(zhǔn)備通信地址成功!"); if(bind(svr_sock,(SP)&svr_addr,addrlen)) { error("bind"); } debug("綁定socket對(duì)象和通信地址成功!"); if(listen(svr_sock,10)) { error("listen"); } debug("設(shè)置監(jiān)聽socket監(jiān)聽成功!"); for(;;) { debug("等待客戶端連接..."); sem_wait(&sem); int index = 0; while(clients[index].sock) { index++; } clients[index].sock = accept(svr_sock,(SP)&clients[index].addr,&addrlen); if(0 > clients[index].sock) { kill(getpid(),SIGINT); } debug("有新的客戶端連接,from ip:%s",inet_ntoa(clients[index].addr.sin_addr)); pthread_create(&clients[index].tid,NULL,run,&clients[index]); } }
客戶端代碼client.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <pthread.h> #include <semaphore.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #ifndef DEBUG #define debug(format,...) {} #else #define debug(format,...) \ {\ fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\ fprintf(stdout,format,##__VA_ARGS__);\ fprintf(stdout,"\n");\ } #endif//DEBUG #define error(format,...)\ {\ fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\ fprintf(stdout,format,##__VA_ARGS__);\ fprintf(stdout,":%m\n");\ exit(EXIT_FAILURE);\ } #define BUF_SIZE 4096 #define SERVER_PORT 5566 #define SERVER_IP "192.168.0.125" typedef struct sockaddr* SP; void* run(void* arg) { int cli_sock = *(int*)arg; char buf[BUF_SIZE] = {}; for(;;) { int ret_size = recv(cli_sock,buf,BUF_SIZE,0); if(0 >= ret_size) { printf("服務(wù)器正在升級(jí),請(qǐng)稍候登錄!\n"); exit(EXIT_SUCCESS); } printf("\r%30s\n>>>",buf); fflush(stdout); } } int main(int argc,const char* argv[]) { int cli_sock = socket(AF_INET,SOCK_STREAM,0); if(0 > cli_sock) { error("socket"); } struct sockaddr_in cli_addr = {}; cli_addr.sin_family = AF_INET; cli_addr.sin_port = htons(SERVER_PORT); cli_addr.sin_addr.s_addr = inet_addr(SERVER_IP); socklen_t addrlen = sizeof(cli_addr); if(connect(cli_sock,(SP)&cli_addr,addrlen)) { printf("服務(wù)器正在升級(jí),請(qǐng)稍候登錄!\n"); return EXIT_SUCCESS; } char buf[BUF_SIZE] = {}; printf("請(qǐng)輸入你的眤稱:"); gets(buf); send(cli_sock,buf,strlen(buf)+1,0); pthread_t tid; pthread_create(&tid,NULL,run,&cli_sock); for(;;) { printf(">>>"); gets(buf); send(cli_sock,buf,strlen(buf)+1,0); if(0 == strcmp("quit",buf)) { printf("退出聊天室!\n"); return EXIT_SUCCESS; } } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Qt串口通信開發(fā)之QSerialPort模塊簡(jiǎn)單使用方法與實(shí)例
這篇文章主要介紹了Qt串口通信開發(fā)之QSerialPort模塊簡(jiǎn)單使用方法與實(shí)例,需要的朋友可以參考下2020-03-03使用pybind11封裝C++結(jié)構(gòu)體作為參數(shù)的函數(shù)實(shí)現(xiàn)步驟
這篇文章主要介紹了用pybind11封裝C++結(jié)構(gòu)體作為參數(shù)的函數(shù)實(shí)現(xiàn)步驟,本文分步驟通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02C++11新特性之智能指針(shared_ptr/unique_ptr/weak_ptr)
這篇文章主要介紹了C++11新特性之智能指針,包括shared_ptr, unique_ptr和weak_ptr的基本使用,感興趣的小伙伴們可以參考一下2016-08-08C/C++?Qt?數(shù)據(jù)庫(kù)與TreeView組件綁定詳解
本篇文章主要介紹了QT數(shù)據(jù)庫(kù)與View組件的綁定,通過(guò)數(shù)據(jù)庫(kù)與組件關(guān)聯(lián)可實(shí)現(xiàn)動(dòng)態(tài)展示數(shù)據(jù)庫(kù)中的表記錄。感興趣的小伙伴可以了解一下2021-12-12C語(yǔ)言實(shí)現(xiàn)第一次防死版掃雷游戲
大家好,本篇文章主要講的是C語(yǔ)言實(shí)現(xiàn)第一次防死版掃雷游戲,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01