Linux下使用C语言实现简单的聊天室程序

news/2024/10/30 13:31:44/

本文章介绍一种基于Linux使用C语言实现简单的局域网聊天室程序的方法,支持消息群发,历史数据查询,好友列表查看,好友上线下线提醒等功能。聊天界面如下图所示:

下面将按步骤介绍该系统的设计实现,首先在linux下创建一个目录,在目录下按顺序创建几个文件,clientlist.c common.h sock.c main.c Makefile,如下图所示,创建完各文件之后,依次在文件里面新增相关的代码内容。

1.在Makefile文件里面添加如下内容:

CC=gcc
CPROG= chat
BIN = $(CPROG) 
OBJS = main.o sock.o clientlist.o
LDFLAGS += -lpthread
CFLAGS    = -I. 
all: $(BIN)
install:$(BIN)@true
uninstall:rm -f $(OBJS) $(BIN)
clean:rm -f $(OBJS) $(BIN)
$(BIN): $(OBJS)$(CC) $(OBJS) $(CFLAGS) $(LDFLAGS) $(CFLAGS_EXTRA) -o $(BIN)

2.在main.c文件里面添加如下内容:

#include <stdio.h>
#include <string.h>
#include "common.h"
void main(int argc, char *argv[])
{if(argc<2) {LOG("input fmt err!\n");return ;}if(!strcmp(argv[1], "s")) {svr_start(SERVER_PORT);}else if(!strcmp(argv[1], "c")) {cli_start(argv);}
}

3.在common.h文件添加如下内容:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <semaphore.h>
#include <arpa/inet.h>
#include <net/if_arp.h>
#include <fcntl.h>#define MAXCLI 10
#define SERVER_PORT 8080
#define USRNAME_LENGTH 32
#define  RGST_INIT 0
#define RGST_OK 1
#define PKG_HEAD 'm'
#define MSG_MODE_LOGIN '0'
#define MSG_MODE_LOGIN_ACK '1'
#define MSG_MODE_SEND '2'
#define MSG_MODE_GET_LIST '3'
#define MSG_MODE_GET_LIST_ACK '4'
#define MSG_MODE_ONLINE '5'
#define MSG_MODE_OFFLINE '6'
#define HISTROY_FILE "h.txt"struct client_chn_s {int skfd;char usrname[USRNAME_LENGTH];CIRCLEQ_ENTRY(client_chn_s) link;
};
typedef struct client_chn_s client_chn_t;
typedef struct svr {int listener;unsigned short port;
}svr_t;typedef struct cli {int sockfd;unsigned char stat;unsigned char history_enable;time_t login_timeout;time_t reconn_timeout;char usrname[USRNAME_LENGTH];char ip[48];unsigned short port;
}cli_t;typedef struct msg_s {unsigned char msgtyp;unsigned char *payload;int payloadlen;unsigned char *username;int username_len;
}msg_t;

4.在sock.c添加如下内容:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <stdarg.h>
#include "common.h"
cli_t cli;
void LOG(const char *format,...)
{va_list argptr;char buffer[2048];va_start(argptr,format);vsprintf(buffer,format,argptr);va_end(argptr);//printf("%s", buffer);
}
/*
Hex打印
*/
void dump_buf(char *label, unsigned char *in, int len)
{int i=0;LOG("%s:\n", label);for(i=0;i<len;i++) {LOG("%02x ", in[i]&0xff);if(0==(i+1)%16) {LOG("\n");}}LOG("\n");
}
void get_cur_time(char *timestamp)
{time_t timep;struct tm *p, pp;time(&timep);localtime_r(&timep, &pp);p = &pp;    sprintf(timestamp,"<%04d-%02d-%02d %02d:%02d:%02d>",p->tm_year + 1900, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
}
void sk_history_record(char *msg)
{FILE *fp = fopen(HISTROY_FILE, "ab+");if(!fp) {LOG("[%s]open %s fail", __func__, HISTROY_FILE);return 0;}fprintf(fp, "%s\r\n", msg);fclose(fp);
}
int sk_tcp_svr_init(int port)
{int yes = 1;struct sockaddr_in svr_addr;int listenfd = -1;if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){        LOG("create socket() fail\n");            return -1;}    if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){        LOG("setsockopt() fail!\n");    exit(0);return -1;    }svr_addr.sin_family = AF_INET;    svr_addr.sin_addr.s_addr = INADDR_ANY;    svr_addr.sin_port = htons(port);memset(&(svr_addr.sin_zero), '\0', 8);if(bind(listenfd, (struct sockaddr *)&svr_addr, sizeof(svr_addr)) == -1){LOG("bind fail!\n");return -1;}if(listen(listenfd, MAXCLI) == -1)        {        LOG("listen fail\n");return -1;}LOG("listen success!!!\n");return listenfd;
}
int sk_start_connect(int *sockfd,char *ip,unsigned short port)
{int i; int iRet;int status;int times=3;struct sockaddr_in host;int    err; int errlen; struct timeval timeout={3,0};fd_set mask;iRet=0;status=-1;*sockfd=-1;if ((0==port) || 0==strlen(ip)){LOG("invalid param");return 0;}host.sin_family=AF_INET; host.sin_port=htons(port); LOG("connect %s:%u\n",ip,port);inet_aton(ip,&host.sin_addr);if ( (*sockfd=socket(AF_INET,SOCK_STREAM,0))<0 ) { LOG("create sock err"); iRet=0;goto err_out; }iRet=connect(*sockfd,(struct sockaddr *)&host,sizeof(host));if(iRet==0) {LOG("connect succ\n");if(fcntl(*sockfd,F_SETFL,O_NDELAY) < 0 ){ LOG("set sock non_block error"); iRet=0;LOG("fcntl err");goto err_out; } return 1;}LOG("iRet:%d\n", iRet);
err_out:return (iRet);
}
int sk_tcp_connect_init(char *svr, int port)
{int iRet, sockfd = -1;iRet=sk_start_connect(&sockfd,svr, port);if (iRet == 0)return -1;return sockfd;
}
int sk_msg_pack(unsigned char *buf, msg_t *m)
{int len = 0;unsigned char msgtype = m->msgtyp;buf[len++] = PKG_HEAD;buf[len++] = msgtype;switch(msgtype){case MSG_MODE_LOGIN:{LOG("[%s][%d]\n",__FUNCTION__,__LINE__);if(m->username_len<=USRNAME_LENGTH) {buf[len++]=m->username_len/256;buf[len++]=m->username_len;memcpy(buf+len, m->username, m->username_len);len+=m->username_len;}LOG("[%s][%d]\n",__FUNCTION__,__LINE__);break;}case MSG_MODE_SEND:{char timestamp[48]="";get_cur_time(timestamp);LOG("[%s][%d]\n",__FUNCTION__,__LINE__);unsigned char msgbuf[1024]="";int msglen = sprintf(msgbuf,"%s%s:%s", m->username, timestamp,m->payload);buf[len++]=msglen/256;buf[len++]=msglen;memcpy(buf+len, msgbuf, msglen);len+=msglen;break;}case MSG_MODE_GET_LIST_ACK:case MSG_MODE_OFFLINE:case MSG_MODE_ONLINE:{buf[len++]=m->payloadlen/256;buf[len++]=m->payloadlen;memcpy(buf+len, m->payload, m->payloadlen);len+=m->payloadlen;break;}}return len;
}
void svr_msg_hander(int fd, unsigned char *in, int len)
{unsigned char msgtyp = in[1];switch(msgtyp){case MSG_MODE_LOGIN:{char usr[USRNAME_LENGTH]="";strcpy(usr, &in[4]);client_chn_add_usr(fd,  usr);msg_t m;m.msgtyp = MSG_MODE_LOGIN_ACK;unsigned char ackbuf[64]="";int acklen = sk_msg_pack(ackbuf, &m);LOG("Send RGST Ack!\n");send(fd, ackbuf, acklen, 0);svr_online_offline_notify(fd,1);break;}case MSG_MODE_SEND:{client_chn_msg_proc(0,in, len);break;}case MSG_MODE_GET_LIST:{char usrlist[1024]="";int ret=client_chn_get_usr_list(usrlist);msg_t m;m.msgtyp = MSG_MODE_GET_LIST_ACK;m.payload = usrlist;m.payloadlen = ret;unsigned char ackbuf[1450]="";int acklen = sk_msg_pack(ackbuf, &m);dump_buf("Send friend list resuest Ack", ackbuf,acklen);send(fd, ackbuf, acklen, 0);break;}}
}
void svr_online_offline_notify(int fd, int isonline)
{client_chn_t *chn = client_chn_get_elm(fd);msg_t m;if(isonline==1) {m.msgtyp = MSG_MODE_ONLINE;}else {m.msgtyp = MSG_MODE_OFFLINE;}char payload[128]="";char timestamp[48]="";get_cur_time(timestamp);if(isonline==1) {sprintf(payload, "%s%s Online!", timestamp, chn->usrname);}else {sprintf(payload, "%s%s Quit!", timestamp, chn->usrname);}m.payload = payload;m.payloadlen = strlen(payload);unsigned char buf[1450]="";int len = sk_msg_pack(buf, &m);dump_buf("notify offline", buf,len);client_chn_msg_proc(fd,buf, len);
}
int svr_recv_proc(int fd)
{unsigned char recvbuf[1450]="";int ret =recv(fd, recvbuf, sizeof(recvbuf), 0);if(ret<=0) {int close_flag = 0;if(ret == 0){/* connection closed */LOG("socket %d close\n", fd);close_flag = 1;}else {if(errno!=EAGAIN) {LOG("recv error!\n");close_flag =1;}}if(close_flag) {svr_online_offline_notify(fd, 0);return -1;}}else {LOG("[clisk:%d]recv %d bytes\n", fd, ret);dump_buf("recv", recvbuf, ret);//client_chn_msg_proc(fd, recvbuf, ret);svr_msg_hander(fd, recvbuf, ret);return ret;}return 0;
}
void svr_accept(svr_t *svr)
{int newfd;struct sockaddr_in clientaddr;int addrlen = sizeof(clientaddr);if((newfd = accept(svr->listener, (struct sockaddr *)&clientaddr, (socklen_t *)&addrlen)) == -1){LOG("accept() error !\n");}else{LOG(" New connection from %s on socket %d\n", inet_ntoa(clientaddr.sin_addr), newfd);client_chn_t *elm = (client_chn_t *)malloc(sizeof(client_chn_t));elm->skfd = newfd;client_chn_insert(elm);}
}
int svr_add_fds(svr_t *svr, fd_set *master)
{int i;int fdmax = 0;if(svr->listener>0) {FD_SET(svr->listener, master);if (svr->listener > fdmax) {fdmax = svr->listener;}}int max = client_chn_add_fds(master);if(fdmax<max) fdmax = max;return fdmax;
}
void svr_select_fd_proc(svr_t *svr, int fd)
{if(svr->listener==fd) {svr_accept(svr);return;}else {if(svr_recv_proc(fd)<0) {client_chn_del(fd);close(fd);}}
}
void svr_start(int port)
{svr_t svr;svr.port=port;svr.listener=sk_tcp_svr_init(port);struct timeval tv, timeo;fd_set master;client_chn_init();while(1) {tv.tv_sec=0;tv.tv_usec=20000;FD_ZERO(&master);int fdmax  = svr_add_fds(&svr, &master);if(select(fdmax+1, &master, NULL, NULL, &tv)<0){LOG("select err\n");}int i;for(i = 0; i <= fdmax; i++){if(FD_ISSET(i, &master)) {LOG("[%s][%d]\n",__FUNCTION__,__LINE__);svr_select_fd_proc(&svr,i);}}}
}
void *cli_input_hander(void *arg)
{while(1) {char msgbuf[1024]="";//scanf("%s", msgbuf);gets(msgbuf);if((cli.sockfd>0)&&(cli.stat==RGST_OK)) {if((strlen(msgbuf)==2)&&(msgbuf[0]=='-')) {switch(msgbuf[1]) {case 'h':{show_help();break;}case 'H':{printf("<---------History----------\n");char cmd[64]="";sprintf(cmd, "cat %s", HISTROY_FILE);system(cmd);printf("--------------------------->\n");break;}case 'q':{printf("Bye!\n");exit(0);break;}case 'g':{char sendbuf[1450]="";char username[32]="";msg_t m;m.msgtyp = MSG_MODE_GET_LIST;int sendlen = sk_msg_pack(sendbuf, &m);dump_buf("send", sendbuf, sendlen);send(cli.sockfd, sendbuf, sendlen, 0);break;}}}else {char sendbuf[1450]="";char username[32]="";msg_t m;m.payload = msgbuf;m.payloadlen=strlen(msgbuf);strcpy(username, cli.usrname);m.username = username;m.username_len = strlen(cli.usrname);m.msgtyp = MSG_MODE_SEND;int sendlen = sk_msg_pack(sendbuf, &m);dump_buf("send", sendbuf, sendlen);send(cli.sockfd, sendbuf, sendlen, 0);}}}
}
void cli_input_start()
{pthread_t thread_id;int ret = pthread_create(&thread_id, NULL, cli_input_hander, NULL);if (ret != 0) {LOG("[%s] create phread fail,%s.\n", __func__, strerror(ret));exit(1);}
}
void cli_login_send(cli_t *c)
{unsigned char logibuf[512]="";unsigned char usrname[32]="";msg_t  m;m.msgtyp = MSG_MODE_LOGIN;sprintf(usrname,"%s",c->usrname);m.username = usrname;m.username_len = strlen(c->usrname);LOG("[%s][%d]\n",__FUNCTION__,__LINE__);int len = sk_msg_pack(logibuf, &m);if(c->sockfd>0) {send(c->sockfd, logibuf, len, 0);}
}
void cli_login_check(cli_t *c)
{if(c->stat==RGST_INIT) {LOG("[%s][%d]\n",__FUNCTION__,__LINE__);cli_login_send(c);}
}
void cli_reconnet_check(cli_t *c)
{if(c->sockfd<0) {LOG("[%s][%d]\n",__FUNCTION__,__LINE__);cli.sockfd = sk_tcp_connect_init(cli.ip,cli.port);if(cli.sockfd>0)cli_login_send(c);}
}
void cli_recv_msg_hander(cli_t *c, unsigned char *msg, int len)
{unsigned char msgtype=msg[1];if(msgtype==MSG_MODE_LOGIN_ACK) {c->stat= RGST_OK;LOG("RGST_OK!\n");}else if(msgtype==MSG_MODE_GET_LIST_ACK) {unsigned char data[1024]="";int datalen = msg[2];datalen=datalen*256+msg[3];memcpy(data, msg+4, datalen);printf("<---------Friends list----------\n");printf("%s", data);printf("-------------------------------->\n");}else if(msgtype==MSG_MODE_SEND||msgtype==MSG_MODE_ONLINE||msgtype==MSG_MODE_OFFLINE||msgtype==MSG_MODE_ONLINE) {unsigned char data[1024]="";int datalen = msg[2];datalen=datalen*256+msg[3];memcpy(data, msg+4, datalen);LOG("recv<==%s\n", data);printf("%s\n", data);if(c->history_enable) {sk_history_record(data);}}
}
int cli_recv_proc(cli_t *c)
{int fd = c->sockfd;unsigned char recvbuf[1450]="";int ret =recv(fd, recvbuf, sizeof(recvbuf), 0);if(ret<=0) {int close_flag = 0;if(ret == 0){/* connection closed */LOG("socket %d close\n", fd);close_flag = 1;}else {if(errno!=EAGAIN) {LOG("recv error!\n");close_flag =1;}}if(close_flag) {return -1;}}else {LOG("[clisk:%d]recv %d bytes, %s\n", fd, ret, recvbuf);cli_recv_msg_hander(c, recvbuf, ret);return ret;}return 0;
}
void cli_start(char *argv[])
{strcpy(cli.ip,"127.0.0.1");cli.port=SERVER_PORT;cli.sockfd = sk_tcp_connect_init(cli.ip,cli.port);cli.stat = RGST_INIT;cli.history_enable = 1;strcpy(cli.usrname, argv[2]);LOG("[%s][%d]cli.usrname:%s\n",__FUNCTION__,__LINE__, cli.usrname);struct timeval tv, timeo;fd_set master;time_t timenow;client_chn_init();cli_input_start();while(1) {tv.tv_sec=0;tv.tv_usec=20000;FD_ZERO(&master);time(&timenow);int fdmax=0;if(cli.sockfd>0) {FD_SET(cli.sockfd, &master);if (cli.sockfd> fdmax) {fdmax = cli.sockfd;}}if(select(fdmax+1, &master, NULL, NULL, &tv)<0){LOG("select err\n");}if(FD_ISSET(cli.sockfd, &master)) {LOG("[%s][%d]\n",__FUNCTION__,__LINE__);if(cli_recv_proc(&cli)<0) {close(cli.sockfd);cli.sockfd = -1;cli.stat=RGST_INIT;}}if(abs(timenow-cli.login_timeout)>=10) {LOG("[%s][%d]\n",__FUNCTION__,__LINE__);cli.login_timeout = timenow;cli_login_check(&cli);}if(abs(timenow-cli.reconn_timeout)>=30) {LOG("[%s][%d]\n",__FUNCTION__,__LINE__);cli.reconn_timeout = timenow;cli_reconnet_check(&cli);}}
}
/*
服务端程序入口
*/
void svr_start(int port)
{    svr_t svr;svr.port=port;svr.listener=sk_tcp_svr_init(port);struct timeval tv, timeo;fd_set master;client_chn_init();while(1) {tv.tv_sec=0;tv.tv_usec=20000;FD_ZERO(&master);int fdmax  = svr_add_fds(&svr, &master);if(select(fdmax+1, &master, NULL, NULL, &tv)<0){LOG("select err\n");}int i;for(i = 0; i <= fdmax; i++){if(FD_ISSET(i, &master)) {LOG("[%s][%d]\n",__FUNCTION__,__LINE__);svr_select_fd_proc(&svr,i);}}}
}
void *cli_input_hander(void *arg)
{while(1) {char msgbuf[1024]="";scanf("%s", msgbuf);if((cli.sockfd>0)&&(cli.stat==RGST_OK)) {char sendbuf[1450]="";char username[32]="";msg_t m;m.payload = msgbuf;m.payloadlen=strlen(msgbuf);strcpy(username, cli.usrname);m.username = username;m.username_len = strlen(cli.usrname);m.msgtyp = MSG_MODE_SEND;int sendlen = sk_msg_pack(sendbuf, &m);dump_buf("send", sendbuf, sendlen);send(cli.sockfd, sendbuf, sendlen, 0);}}
}
void cli_input_start()
{pthread_t thread_id;int ret = pthread_create(&thread_id, NULL, cli_input_hander, NULL);if (ret != 0) {LOG("[%s] create phread fail,%s.\n", __func__, strerror(ret));exit(1);}
}
void cli_login_send(cli_t *c)
{unsigned char logibuf[512]="";unsigned char usrname[32]="";msg_t  m;m.msgtyp = MSG_MODE_LOGIN;sprintf(usrname,"%s",c->usrname);m.username = usrname;m.username_len = strlen(c->usrname);LOG("[%s][%d]\n",__FUNCTION__,__LINE__);int len = sk_msg_pack(logibuf, &m);if(c->sockfd>0) {send(c->sockfd, logibuf, len, 0);}
}
void cli_login_check(cli_t *c)
{if(c->stat==RGST_INIT) {LOG("[%s][%d]\n",__FUNCTION__,__LINE__);cli_login_send(c);}
}
void cli_reconnet_check(cli_t *c)
{if(c->sockfd<0) {LOG("[%s][%d]\n",__FUNCTION__,__LINE__);cli.sockfd = sk_tcp_connect_init(cli.ip,cli.port);if(cli.sockfd>0)cli_login_send(c);}
}
void cli_recv_msg_hander(cli_t *c, unsigned char *msg, int len)
{unsigned char msgtype=msg[1];if(msgtype==MSG_MODE_LOGIN_ACK) {c->stat= RGST_OK;LOG("RGST_OK!\n");}else if(msgtype==MSG_MODE_SEND) {unsigned char data[1024]="";int datalen = msg[2];datalen=datalen*256+msg[3];memcpy(data, msg+4, datalen);LOG("recv<==%s\n", data);printf("<==%s\n", data);}
}
/*
客户端数据接收
*/
int cli_recv_proc(cli_t *c)
{int fd = c->sockfd;unsigned char recvbuf[1450]="";int ret =recv(fd, recvbuf, sizeof(recvbuf), 0);if(ret<=0) {int close_flag = 0;if(ret == 0){/* connection closed */LOG("socket %d close\n", fd);close_flag = 1;}else {if(errno!=EAGAIN) {LOG("recv error!\n");close_flag =1;}}if(close_flag) {return -1;}}else {LOG("[clisk:%d]recv %d bytes, %s\n", fd, ret, recvbuf);cli_recv_msg_hander(c, recvbuf, ret);return ret;}return 0;
}
/*
客户端程序入口
*/
void cli_start(char *argv[])
{strcpy(cli.ip,"127.0.0.1");cli.port=SERVER_PORT;cli.sockfd = sk_tcp_connect_init(cli.ip,cli.port);cli.stat = RGST_INIT;strcpy(cli.usrname, argv[2]);LOG("[%s][%d]cli.usrname:%s\n",__FUNCTION__,__LINE__, cli.usrname);struct timeval tv, timeo;fd_set master;time_t timenow;client_chn_init();cli_input_start();while(1) {tv.tv_sec=0;tv.tv_usec=20000;FD_ZERO(&master);time(&timenow);int fdmax=0;if(cli.sockfd>0) {FD_SET(cli.sockfd, &master);if (cli.sockfd> fdmax) {fdmax = cli.sockfd;}}if(select(fdmax+1, &master, NULL, NULL, &tv)<0){LOG("select err\n");}if(FD_ISSET(cli.sockfd, &master)) {if(cli_recv_proc(&cli)<0) {close(cli.sockfd);cli.sockfd = -1;cli.stat=RGST_INIT;}}if(abs(timenow-cli.login_timeout)>=10) {//定时检查登录状态cli.login_timeout = timenow;cli_login_check(&cli);}if(abs(timenow-cli.reconn_timeout)>=30) {//定时检查连接状态cli.reconn_timeout = timenow;cli_reconnet_check(&cli);}}
}

5.在clientlist.c添加如下内容:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <semaphore.h>
#include <arpa/inet.h>
#include <net/if_arp.h>
#include <fcntl.h>
#include "common.h"
static CIRCLEQ_HEAD(client_Head, client_chn_s) client_head;
void client_chn_init(void)
{CIRCLEQ_INIT(&client_head);
}
void client_chn_insert(client_chn_t *elm)
{CIRCLEQ_INSERT_HEAD(&client_head, elm, link);
}
void client_chn_del(int skfd)
{struct client_chn_s *chn;for (chn = client_head.cqh_first; chn != (void *)&client_head;chn = chn->link.cqe_next) {if (chn->skfd== skfd) {CIRCLEQ_REMOVE(&client_head, chn, link);free(chn);break;}}}
int client_chn_add_usr(int skfd, char *usr)
{struct client_chn_s *chn;int ret=0;for (chn = client_head.cqh_first; chn != (void *)&client_head;chn = chn->link.cqe_next) {if(chn->skfd==skfd) {sprintf(chn->usrname, "%s\n",usr);LOG("[%s](%d)add user:%s\n", __func__, __LINE__, chn->usrname);}}return ret;
}
int client_chn_add_fds(fd_set *master)
{int i;int fdmax = 0;struct client_chn_s *chn;for (chn = client_head.cqh_first; chn != (void *)&client_head;chn = chn->link.cqe_next) {if(chn->skfd>fdmax) fdmax = chn->skfd;FD_SET(chn->skfd, master);}return fdmax;
}
void client_chn_print()
{struct client_chn_s *chn;for (chn = client_head.cqh_first; chn != (void *)&client_head;chn = chn->link.cqe_next) {LOG("[%s](%d)skfd:%d\n", __func__, __LINE__, chn->skfd);}
}
client_chn_t *client_chn_get_elm(int fd)
{struct client_chn_s *chn;for (chn = client_head.cqh_first; chn != (void *)&client_head;chn = chn->link.cqe_next) {if(chn->skfd==fd) {return chn;} }return NULL;
}
int client_chn_msg_proc(int fd, unsigned char *in, int len)
{struct client_chn_s *chn;for (chn = client_head.cqh_first; chn != (void *)&client_head;chn = chn->link.cqe_next) {if(fd>0) {if(chn->skfd!=fd) {send(chn->skfd, in, len, 0);}}else {send(chn->skfd, in, len, 0);}}
}
int client_chn_get_usr_list(char *out)
{struct client_chn_s *chn;int ret=0;int cnt=0;for (chn = client_head.cqh_first; chn != (void *)&client_head;chn = chn->link.cqe_next) {cnt++;ret+=sprintf(out+ret, "%d:%s", cnt, chn->usrname);LOG("[%s](%d)pack user:%s\n", __func__, __LINE__, chn->usrname);}return ret;
}

6.代码编译:

make clean

make

最后生成“chat”可执行文件,用户便可以在Linux环境下启用聊天室了。

7.启动聊天室步骤(这里以三个用户为例子)

7.1启用后台服务端

7.2依次启动三个客户端

至此,所有接入该聊天室的用户都可以开始使用聊天室的基本功能了。

总结:该程序使用了大家熟悉的TCP协议,通过客户端/服务端的方式,在Linux系统下使用C语言实现简单的局域网聊天室的功能,该功能的实现过程中可以让初学者熟悉Linux下socket编程以及不同设备之间的以太网通信机制,为以后做其它的项目打下基础并积累一些经验。


http://www.ppmy.cn/news/29879.html

相关文章

Python3,好看的外(shen)表(cai)千篇一律,炫彩的日志万里挑一。

炫彩日志输出1、引言2、代码实战2.1 库介绍2.2 库安装2.3 代码示例2.3.1 demo2.3.2 实战3、总结1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 我今天被炫到了。 小鱼&#xff1a;怎么了&#xff0c;你还能被旋到了&#xff1f; 小屌丝对啊&#xff0c; 被炫到了&#xff0c;很…

Cadence Allegro 导出Bill of Material Report详解

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,Bill of Material Report作用3,Bill of Material Report示例4,Bill of Material Report导出方法4.1,方法14.2,方法2B站关注“硬小二”浏览更多演示视频

首发,pm3包,一个用于多组(3组)倾向评分匹配的R包

目前&#xff0c;本人写的第二个R包pm3包已经正式在CRAN上线&#xff0c;用于3组倾向评分匹配&#xff0c;只能3组不能多也不能少。 可以使用以下代码安装 install.packages("pm3")什么是倾向性评分匹配&#xff1f;倾向评分匹配&#xff08;Propensity Score Match…

Python 元类编程实现一个简单的 ORM

概述 什么是ORM?    ORM全称“Object Relational Mapping”&#xff0c;即对象-关系映射&#xff0c;就是把关系数据库的一行映射为一个对象&#xff0c;也就是一个类对应一个表&#xff0c;这样&#xff0c;写代码更简单&#xff0c;不用直接操作SQL语句。 现在我们就要实…

React(三):脚手架、组件化、生命周期、父子组件通信、插槽、Context

React&#xff08;三&#xff09;一、脚手架安装和创建1.安装脚手架2.创建脚手架3.看看脚手架目录4.运行脚手架二、脚手架下从0开始写代码三、组件化1.类组件2.函数组件四、React的生命周期1.认识生命周期2.图解生命周期&#xff08;1&#xff09;Constructor&#xff08;2&…

python的 ping 网络状态监测方法(含多IP)

ping 基本概念 ping &#xff08;Packet Internet Groper&#xff09;是一种因特网包探索器&#xff0c;用于测试网络连接量的程序。Ping是工作在 TCP/IP网络体系结构中应用层的一个服务命令&#xff0c; 主要是向特定的目的主机发送 ICMP&#xff08;Internet Control Messag…

simulink PID控制

系列文章目录 文章目录系列文章目录前言一、非线性系统线性化原理二、反馈控制开环控制反馈or闭环控制PID ControllerPID微调案例总结前言 将非线性系统近似线性化PIDblock与微调 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、非线性系统线性化 …

Linux操作系统学习(进程替换)

文章目录进程替换进程替换是什么&#xff1f;替换的方法进程替换简易shell模拟进程替换 进程替换是什么&#xff1f; 如下图所示&#xff1a; ​ 进程替换就是&#xff0c;把进程B的代码和数据&#xff0c;替换正在执行的进程A的代码和数据在内存中的位置&#xff08;若代码…