基于linux下的聊天程序设计与实现一、 实现的内容及要求: 用C语言编程实现linux简单的聊天室功能。 用户程序命名为client.c;服务器程序命名为server.c 绑定端口等信息见实验方法内容; 要求client可以通过socket连接server 在client,提示输入服务器ip 若连接server 的socket建立成功,返回提示信息 Client输入的聊天内容在client端(多个client端)和server端同时显示; 多个client可同时接入server,进入聊天室,最多支持20个client; Client端输入quit退出连接,server端提示client退出。 可选择使用多线程实现多客户端; 其他细节见输出结果; 二、方法及内容1. 需要的头文件#include#include#include#include#include#include#include#include#include#include#include 2. 主要的常量变量客户端:#define TRUE 1#define PORT 5000int quit=0; //quit表示是否用户确定退出 服务器端:#define MAXLINE 1000 //在一条消息中最大的输出字符数#define LISTENQ 20 //最大监听队列#define PORT 5000 //监听端口#define MAXFD 20 //最大的在线用户数量void *get_client(void *); int i,maxi=-1;//maxi表示当前client数组中最大的用户的i值int client[MAXFD];3.主要模块客户端:intmain(void)void*get_server(void* sockfd) //get_server函数,用于接受服务器转发的消息服务器端: intmain() void*get_client(void *sockfd) //运行get_client函数,处理用户请求 三.完整代码实现注:参考socket编程 /******* 客户端程序client.c ************/#include#include#include#include#include#include#include#include #define TRUE 1#define PORT 5000 static int sockfd;void recvfromserver() //接受服务器消息线程入口函数{ charmes[1024]; int nbytes=0; while(1) { memset(mes,0,sizeof(mes)); nbytes=read(sockfd,mes,sizeof(mes)); if(nbytes>0) { mes[nbytes]=''; printf("%sn",mes); } } pthread_exit(NULL);} int main(int argc, char *argv[]){// int sockfd; charbuffer[1024]; structsockaddr_in server_addr; structhostent *host; intportnumber,nbytes; charstrhost[16]; charclientname[20]; charmes[1024]; int thr_id; /* thread ID for the newly createdthread */ pthread_t p_thread; /* thread's structure */ if(argc!=1) { fprintf(stderr,"Usage:%san",argv[0]); exit(1); } printf("请输入服务器ip地址n"); scanf("%s",strhost); if((host=gethostbyname(strhost))==NULL) { fprintf(stderr,"Gethostnameerrorn"); exit(1); } /* 客户程序开始建立 sockfd 描述符 */ printf("正在建立套接口...n"); if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { fprintf(stderr,"SocketError:%san",strerror(errno)); exit(1); } /* 客户程序填充服务端的资料 */ bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_port=htons(PORT); server_addr.sin_addr=*((structin_addr *)host->h_addr); printf("套接口创建成功,正在链接服务器...n"); /* 客户程序发起连接请求 */ if(connect(sockfd,(structsockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) { fprintf(stderr,"ConnectError:%san",strerror(errno)); exit(1); } /* 连接成功了 */ printf("链接服务器成功n欢迎来到聊天室n"); printf("请输入你的用户昵称n"); scanf("%s",clientname);// write(sockfd,clientname,sizeof(clientname)); printf("nn开始聊天吧("Quit"断开连接)nn"); thr_id =pthread_create(&p_thread, NULL, recvfromserver, NULL); while(1) { memset(buffer,0,sizeof(buffer)); memset(mes,0,sizeof(mes)); scanf("%s",buffer); strcat(mes,clientname); strcat(mes,":"); strcat(mes,buffer); // printf("main thread %sn",mes); if((write(sockfd,mes,sizeof(mes)))==-1) { fprintf(stderr,"WriteError:%sn",strerror(errno)); exit(1); } if(strcmp(buffer,"Quit")==0) { break; } } /* 结束通讯 */ close(sockfd); exit(0);} /******* 服务器程序(server.c) ************/#include#include#include#include#include#include#include#include #define MAXLINE 1000 //在一条消息中最大的输出字符数#define LISTENQ 20 //最大监听队列#define PORT 5000 //监听端口#define MAXFD 20 //最大的在线用户数量void *get_client(void *); int sockfd,i;static int maxi=0;//maxi表示当前client数组中最大的用户的i值static int client[MAXFD]; void recvandsend(void) //监听转发线程入口函数{ int index=0; int nbytes=0; charbuffer[1024]; int len; intoutindex=0; while(1) { if(maxi>0) { memset(buffer,0,sizeof(buffer)); nbytes=0; //index++; nbytes=read(client[index++],buffer,sizeof(buffer));// printf("%d,%dn",index,client[index]); if(nbytes>0) { buffer[nbytes]=''; printf("%sn",buffer); outindex=0; while(outindex=maxi) index=0; } pthread_exit(NULL);} int main(int argc, char *argv[]){// intclient_fd[LISTENQ],clientnum=0;; structsockaddr_in server_addr; structsockaddr_in client_addr; intsin_size,portnumber; charhello[]="Hello! Are You Fine?n"; int thr_id; /* thread ID for the newly createdthread */ pthread_t p_thread; /* thread's structure */ int new_fd=0; memset(client,0,sizeof(client)); if(argc!=1) { fprintf(stderr,"Usage:%sportnumberan",argv[0]); exit(1); } /* 服务器端开始建立 socket 描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { fprintf(stderr,"Socketerror:%sna",strerror(errno)); exit(1); } /* 服务器端填充 sockaddr 结构 */ bzero(&server_addr,sizeof(structsockaddr_in)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); server_addr.sin_port=htons(PORT); /* 捆绑 sockfd 描述符 */ if(bind(sockfd,(structsockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) { fprintf(stderr,"Binderror:%sna",strerror(errno)); exit(1); } printf("服务器监听端口%d...n",PORT); /* 监听 sockfd 描述符 */ if(listen(sockfd,LISTENQ)==-1) { fprintf(stderr,"Listenerror:%sna",strerror(errno)); exit(1); } thr_id =pthread_create(&p_thread, NULL, recvandsend, NULL); printf("欢迎来到本聊天室n"); while(1) { /* 服务器阻塞,直到客户程序建立连接 */ if(maxi>=20) { printf("以达到人数上线n"); continue; } sin_size=sizeof(structsockaddr_in); if((new_fd=accept(sockfd,(structsockaddr *)(&client_addr),&sin_size))==-1) { fprintf(stderr,"Accepterror:%sna",strerror(errno)); exit(1); } /*fprintf(stderr,"Serverget connection from %sn",inet_ntoa(client_addr.sin_addr));*/ client[maxi++]=new_fd; printf("n新用户进入聊天室%dn",new_fd); } close(sockfd); exit(0);} 四、测试结果显示1. 执行结果l 服务器打开l 客户端打开,并输入了地址,昵称l 服务器端显示l 客户端2进入l 服务器显示l 张三输入l 李四端显示l 服务器显示l 李四输入l 张三显示l 服务器显示2. 结果分析 这是一个聊天室程序,可以实现群聊的功能,即当某个客户发出消息后,服务器和其他个客户端都能收到此消息。且能够显示客户端的用户名。但客户端退出聊天室后,服务器和其他在线客户端会有提示。 实现群聊的机制是:当某个客户端需要发送消息是,它将此消息发送给服务器,服务器再将此消息转发给各客户端,各客户端之间是无连接的,即相互之间不能直接通信。因此,在服务器中,有两个线程,主线程用来监听是否有客户端登录服务器,若有,建立与其连接的套接字,并存入在线客户序列里,辅助线程是接收转发线程,其依次读取个客户端,看是否有消息送达,若有,取出,并转发给各其他客户端。在客户端也有两个线程,主线程用来向服务器发送消息,辅助线程用来接收服务器发出的消息。 存在的问题是:1.当有用户下线是,虽会在服务器和各客户端提示用户下线,但是并未删除其在服务器中的套接字,致使后来用户不能进入。2.服务器的辅助线程对各客户端采取轮流监听的策略,但是因为使用read() 函数会阻塞线程,致使出现各客户端必须按登陆顺序依次发言的尴尬情况。经过查找,可以使用select()函数跨过阻塞,正在试验中。 不足之处,欢迎指正!欢迎交流!
时间:2018-11-21
本文介绍了一个基于Linux的简单聊天室程序的设计与实现。该程序采用C语言编写,支持多客户端接入,通过服务器转发消息实现群聊功能。客户端与服务器间通过socket进行通信。
5527

被折叠的 条评论
为什么被折叠?



