socket-多人聊天室 Linux

  1. 实验内容
    本系统实现一个基于Linux的模拟即时通信系统,要求实现以下功能:
    1、模拟即时通信系统可以实现多人同时在线聊天功能;
    2、在线聊天用户登录本系统需输入用户名和密码;
    3、本系统需能够查询历史聊天记录;
    4、本系统运行后,需启动一个守护进程,该守护进程记录本系统启动和关闭的时间,每个用户登录和退出时间;
    5、需创建本系统的Makefile管理文件,管理系统源码。
  2. 实验结果
    

1、功能需求:
该聊天工具是在Linux平台下进行开发与实现的,可以实现多人通信和交流。系统采用了TCP/IP协议和socket接口。从总体来讲,该聊天系统主要包括服务端与客户端。
服务端功能实现模块:
 用户通过用户名和密码进行登录
 等待客户端进行身份验证,登录
 接收和发送用户聊天信息功能(接受发信用户发来的信息,再将信息转发到收信用户)
客户端功能实现模块:
 验证登录用户的信息
 客户端之间进行信息传递交流
 保存聊天记录
2、功能模块图:
(1) 服务器端:
服务器端登录时与用户名和密码相关联,成功登陆后,可以开启多个客户端,服务器端通过send()函数来向客户端发送服务器端开启的消息,通过accept()接收了客户端连接的请求,连接成功,实现了多人在线聊天的功能。发送消息时,将存储的消息以char *的形式通过函数给socket通信。接收消息时,当有消息传来,通过recv()函数先检查套接字sock的接收缓冲区,如果sock的接收缓冲区中没有数据或者协议正在接收数据,那么recv就一起等待,直到把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲区中的数据copy到rbuf中,可以显示在聊天界面的文本框内。
在这里插入图片描述

(2) 客户端:
多个客户端在和服务器端连接成功后,开始进行多人在线聊天,通过checklogin()函数实现用户名和密码匹配,从而实现用户登录,验证完之后开始进行多人聊天,通过save()函数将聊天记录保存Loginfo.txt
同样用户发送消息时通过send()函数向服务器端发送消息,通过recv()函数来接收消息内容。
在这里插入图片描述

(3) 系统总结构:

在这里插入图片描述

  1. 各部分代码:
    server.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include<time.h>

#define PORT 54188
#define MAX_CLIENT 10
client.c:
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<time.h>

	服务器端代码:
Server.c:
struct client{
	int s;
	char name[50];
	int online;
};

static int sock;
static char rbuf[1024];
static char wbuf[1024];

static struct sockaddr_in server,client;
static struct client cli[MAX_CLIENT];


int main(int argc,char *argv[]){
	int max_sock;
	int len;
 	
	
 

	sock=socket(AF_INET,SOCK_STREAM,0);
	if(sock==-1){
		perror("socket");
		return 1;
	}

	max_sock=sock;

	bzero(&server,sizeof(server));
	server.sin_port=htons(PORT);
	server.sin_addr.s_addr=INADDR_ANY;
	server.sin_family=AF_INET;
	if(bind(sock,(struct sockaddr *)&server,sizeof(struct sockaddr))==-1){
		perror("bind");
		return 2;
	}

	listen(sock,MAX_CLIENT);
	
	int i=0,j=0;
	fd_set rfd;
	while(1){
		FD_ZERO(&rfd);
		FD_SET(sock,&rfd);
		for(i=0;i<MAX_CLIENT;i++){
			if(cli[i].s==0)
				continue;
			FD_SET(cli[i].s,&rfd);
		}
		switch(select(max_sock+1,&rfd,NULL,NULL,NULL)){
			case 0:
				continue;
			case -1:
				continue;
			default:
				if(FD_ISSET(sock,&rfd)){
					for(i=0;i<MAX_CLIENT;i++){
						if(cli[i].s==0){
						len=sizeof(struct sockaddr);
				cli[i].s=accept(sock,(struct sockaddr *)&client,&len);
							if(cli[i].s==-1){
								perror("accept");
								cli[i].s=0;
								break;
							}
							cli[i].online=0;
							if(cli[i].s>max_sock)
								max_sock=cli[i].s;
							printf("accept!\n");
							break;
						}
					}
				}
		
	for(i=0;i<MAX_CLIENT;i++){
	if(cli[i].s==0)
	continue;
	if(FD_ISSET(cli[i].s,&rfd)){
	int rsize;
	bzero(rbuf,sizeof(rbuf));
        rsize=recv(cli[i].s,rbuf,sizeof(rbuf),0);
        if(rsize>0){
	printf("%s\n",rbuf);
	if(cli[i].online){
	for(j=0;j<MAX_CLIENT;j++){
	if(cli[j].s==0 || j==i || cli[j].online==0)
	continue;
        bzero(wbuf,sizeof(wbuf));
	strcpy(wbuf,cli[i].name);
	strcat(wbuf,rbuf);
	send(cli[j].s,wbuf,strlen(wbuf)+rsize,0);
							}
		if(!strcmp(rbuf,"bye\n")){
		send(cli[i].s,"quit",4,0);
		close(cli[i].s);
		cli[i].s=0;
		cli[i].online=0;
		memset(cli[i].name,0,sizeof(cli[i].name));
							}
						}
 			else{
				if(!strncmp(rbuf,"#name",5)){
				
				strcpy(cli[i].name,rbuf+5);
				
				cli[i].online=1;
							}
						}
					}
				}
			}
		}
	}
	return 0;
}

Client.c:

int main(int argc,char *argv[]){
	FILE *fp;
	char logname[100];
 	char pwd[100];
 	int temp;
        printf("please input username:");
        scanf("%s",&logname);
        printf("please input password:");
        scanf("%s",&pwd);
 if(checklogin(logname, pwd, temp) == 0)
        return 0;
	int i,j,err;
	char name[100];
	int rsize,wsize;
	sock=socket(AF_INET,SOCK_STREAM,0);
	if(sock==-1){
		perror("socket");
		return 1;
	}
	
	bzero(&server,sizeof(server));
	server.sin_family=AF_INET;
	server.sin_addr.s_addr=inet_addr("127.0.0.1");
	server.sin_port=htons(54188);
	err=connect(sock,(struct sockaddr *)&server,sizeof(struct sockaddr));
	if(err==-1){
		perror("connect");
		return 2;
	}
	printf("connect success!\n");
	bzero(rbuf,sizeof(rbuf));
	bzero(name,sizeof(name));
	rsize=read(STDIN_FILENO,rbuf,sizeof(rbuf));
	rbuf[strlen(rbuf)-1]='\0';
	sprintf(name,"#name%s:",rbuf);

	send(sock,name,sizeof(name),0);
	
	j=0;i=0;
	fd_set rfd;
	FD_ZERO(&rfd);
	FD_SET(STDIN_FILENO,&rfd);
	FD_SET(sock,&rfd);
	while(1){

		FD_ZERO(&rfd);
		FD_SET(STDIN_FILENO,&rfd);
		FD_SET(sock,&rfd);

	switch(select(sock+1,&rfd,NULL,NULL,NULL)){
			case -1:
			case 0:
			continue;
			default:
       if(FD_ISSET(STDIN_FILENO,&rfd)){
		bzero(rbuf,sizeof(rbuf));
		rsize=read(STDIN_FILENO,rbuf,sizeof(rbuf));
		if(rsize>0){
			send(sock,rbuf,rsize,0);
			 save(name,rbuf);
					}
				}

		if(FD_ISSET(sock,&rfd)){
		bzero(rbuf,sizeof(rbuf));
		rsize=recv(sock,rbuf,sizeof(rbuf),0);
		if(rsize>0){
		printf("\033[34m%s\033[30m\n",rbuf);
			if(!strcmp(rbuf,"quit")){
				close(sock);
				return 11;
						}
							
					}
				}
		}
	}
	return 0;
}

 保存聊天记录:
Client.c:

void save(char name[],char s[])
{
        time_t t;
        char buf[1024];
        FILE *fp;
	int i;
 	int n;
 	fp=fopen("record.txt","a");
 	if(!fp)
 	{
  	printf("file open fail!");
  	exit(0);
	 }
 	time(&t);
        ctime_r(&t,buf);   
        fprintf(fp,"%s",buf);
	fprintf(fp,"%s",name);
 	fprintf(fp,"%s",s);
 	fclose(fp);
 	printf("data save successfull\n");
	}

 用户名和密码登录:
Client.c:

int checklogin(char *loginname,char *loginpassword,int flag){
 FILE *fp;
 char user_name[100],user_pwd[100];
  if(!(fp = fopen("/home/test/src/keshe/Loginfo.txt","r"))){
  perror("file open error!");
  return 0;
}
while(fscanf(fp,"%s %s",user_name,user_pwd)!=EOF){
if(!strcmp(loginname, user_name) && !strcmp(loginpassword, user_pwd))
     return 1;
}
 fclose(fp);
 return 0;
}

 将系统开启时间记录到日志中:
Server.c:

char tm[1024];
FILE *fp;
time_t  t;
fp=fopen("demo.log","a");
 if(!fp)
  {
   		printf("file open fail!");
   		exit(0);
  	}
  		time(&t);
        ctime_r(&t,tm);   
       fprintf(fp, "%s the chat system start", tm); 

 Makefile文件:

target:server.o client.o
	gcc -o server server.o
	gcc -o client client.o

server.o:server.c
	gcc -c -o server.o server.c

client.o:client.c
	gcc -c -o client.o client.c

clean:
	rm *.o server client

.PHONY:clean

 储存聊天记录文件 Loginfo.txt

  1. 运行结果:
    在这里插入图片描述
    5.问题分析与总结:

本次Linux期末采取了大作业的方式,老师布置了做一个简易的多人在线聊天系统。确实对于编程能力很弱的我,出现了很多问题,而且对于老师的要求有的完成的不够全面。
首先,开始对socket原理不是很熟悉,只是上课老师让我们练习过几次,但根据网上查阅的资料,也顺利的完成了多人在线聊天的功能。之后开始完成用户登录这一项功能,但是遇到了很多问题,无法进行注册功能,所以登录功能不是很完善,只能做到在.txt文件中输入用户信息和密码,然后在登录的时候去和文件中的信息进行匹配,完成了一个登录功能,后续功能还需要继续完善。接下来就是保存聊天记录功能,这个功能是将客户发送信息给写进文件中,开始只能将聊天内容保存,但是不能区分是哪个用户说的,后来通过写入用户姓名,和服务器端做了一个连接,解决了这一问题,后来还练习了获取系统时间函数,成功保存了时间、客户姓名和内容记录。但是唯一最后没有解决的是守护进程的编写,没有成功建立服务器端。所以此项功能没有实现,在此说明一下,后续会继续研究,将功能完善。
此次编写程序,不仅让我巩固了这学期所学的Linux的知识,而且更加熟练的掌握了socket(套接字)的用法,而且还掌握了一些以前不熟悉的操作,比如文件的写入,获取系统时间等等,所以通过这次实验收获还是很多的,对自己动手能力也是有了很大的提高,但是还有很多不足,以后慢慢改善。

  • 3
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值