Linux下C实现的聊天室

七年前写的练手程序,好不容易翻出来,回过头来看当年的代码,感慨良多。源码在文末,分享一下,谢谢。

 

============================================================================================

实现目标

一个在Linux下可以使用的聊天软件,要求至少实现如下功能:
1. 采用Client/Server架构
2. Client A 登陆聊天服务器前,需要注册自己的ID和密码
3. 注册成功后,Client A 就可以通过自己的ID和密码登陆聊天服务器
4. 多个Client X 可以同时登陆聊天服务器之后,与其他用户进行通讯聊天
5. Client A成功登陆后可以查看当前聊天室内其他在线用户Client x
6. Client A可以选择发消息给某个特定的Client X,即”悄悄话”功能
7. Client A 可以选择发消息全部的在线用户,即”群发消息”功能
8. Client A 在退出时需要保存聊天记录
9. Server端维护一个所有登陆用户的聊天会的记录文件,以便备查
可以选择实现的附加功能:
1. Server可以内建一个特殊权限的账号admin,用于管理聊天室
2. Admin可以将某个Client X “提出聊天室”
3. Admin可以将某个Client X ”设为只能旁听,不能发言”
4. Client 端发言增加表情符号,可以设置某些自定义的特殊组合来表达感情.如输入:),则会自动发送”XXX向大家做了个笑脸”
5. Client段增加某些常用话语,可以对其中某些部分进行”姓名替换”,例如,输入/ClientA/welcome,则会自动发送”ClientA 大侠,欢迎你来到咱们的聊天室”

附加功能:

文件传输

部分主要代码:

客户端:

client_main.h

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#define PORT 6666
#define MAXLEN 1000
#define OK 1
#define FAULT 0
struct message    /*消息结构体*/
{
    char flag[15];             /*标志位*/
    char name[20];             /*用户名*/
	char msg[MAXLEN];          /*消息内容*/
	char addressee[20];        /*传输文件目的用户*/
	int size;                  /*传输内容字节数*/
};
int qid = -1,fd = -1;
int sockfd = -1;               /*套接字描述符*/
int savefilefd = -1;           /*保存文件描述符*/
char filefromname[20];         /*文件来源名*/
char chat_log[100];            /*聊天记录名*/
pthread_mutex_t lock ;         /*线程锁*/

 

 

 

 

 

client_handle.h

 

#ifndef CLIENT_HANDLE_H
#define CLIENT_HANDLE_H

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#define PORT 8888
#define MAXLEN 1000
#define OK 1
#define FAULT 0
struct message    /*消息结构体*/
{
    char flag[15];             /*标志位*/
    char name[20];             /*用户名*/
	char msg[MAXLEN];          /*消息内容*/
	char addressee[20];        /*传输文件目的用户*/
	int size;                  /*传输内容字节数*/
};
extern int qid,fd;
extern int sockfd;               /*套接字描述符*/
extern int savefilefd;           /*保存文件描述符*/
extern char filefromname[20];    /*文件来源名*/
extern char chat_log[100];       /*聊天记录名*/
extern pthread_mutex_t lock ;    /*线程锁*/
char filefromuser[20];           /*文件发送者用户名*/
char locname[20];                /*本客户端用户名*/

int Interface();
void cutStr(char str[],char left[], int n, char right[],int m, char c);
int help(char str[]);
void expression(char name[],char msg[]);
void common_use_words(char msg[]);
void handlesendfile();
void handlerecvfile(struct message *msg);
void handlerecvmsg(int *sockfd);
int admin_kick(int sockfd,struct message *a);
int admin_screen(int sockfd,struct message *a);
int login_admin(struct message *a);
int login_success(struct message *a);
int Register(struct message *a);
void log_user(struct message *a);

#endif //CLIENT_HANDLE_H

 

 

 

 

 

my_system_call.h

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>

 

 

client_main.c

 

 

/***************************************************
File name: client.c
Author:Chenchunjian
Data:2012
Description:聊天软件客户端main函数
***************************************************/
#include "../../include/client_main.h"

int main(int argc, char *argv[])
{
	int ret;
    int do_number;
    char str[MAXLEN];
    char buf[MAXLEN];
	char buf_new[100];
    struct message msg;
	struct message a;
	struct sockaddr_in my_addr;
    time_t timep;
	enum action{log=1,reg,ex};
	struct hostent *host;
    if(argc!=2)
	{
		fprintf(stderr,"Usage:%s hostname \a\n",argv[0]);
		exit(1);
	}
	if((host=gethostbyname(argv[1]))==NULL)
	{
		fprintf(stderr,"Gethostname error\n");
		exit(1);
	}
	while(1)
	{
		if((sockfd=my_socket(PF_INET,SOCK_STREAM,0)) < 0)  /*创建套接字,使用TCP协议*/
	    {
	        exit(-1);
	    }
		bzero(&my_addr,sizeof(struct sockaddr_in));      /*清空地址结构*/
		my_addr.sin_family = AF_INET;                     /*使用IPV4通信域*/
		my_addr.sin_port = htons(PORT);                   /*端口号转换为网络字节序*/
		my_addr.sin_addr = *((struct in_addr *)host->h_addr);      /*可接受任意地址*/
		if(my_connect(sockfd,(struct sockaddr *)(&my_addr),sizeof(my_addr)) == -1)  /*主动连接服务器*/
		{
			printf("正在连接,请稍等……\n");
			exit(1);
		}
	    do_number = Interface();     /*登录界面*/
	    switch(do_number)
        {
            case log:               /*登录*/
		        {
					 int n = 3;
					 while(n)
					 {
					     log_user(&a);
						 if(my_strcmp(a.msg,"hello,admin!") == 0)    /*管理员登录成功*/
						 {
						     if(login_admin(&a) == 0)
						     {
						         return FAULT;
						     }
						 }
						 if(my_strcmp(a.msg,"login,success!") == 0)   /*用户登录成功*/
						 {
						    if(login_success(&a) == FAULT)
						    {
								return FAULT;
						    }
						 }
						 else                                       /*登录未成功*/
						 {
					         n--;
							 printf("你还有 %d次机会!\n",n);
						 }
					}
					my_close(sockfd);
					exit(3);
				    break;
			    }
		    case reg:     /*注册*/
		    	{
					Register(&a);
	                break;
		    	}
		    case ex:      /*退出*/
		    	{
			    	my_close(sockfd);
				    printf("离开聊天室!\n");
    				break;
	    		}
		    default:
    			{
	    			break;
		    	}
	    }
	}
    my_close(sockfd);
    return FAULT;
}


admin.c

 

 

 

 

#include "../../include/client_handle.h"

/***************************************************
函数名:admin_chat
功能:管理员聊天功能
传入参数:int sockfd,struct message *a
返回值:退出返回FAULT
***************************************************/
int admin_chat(int sockfd,struct message *a)  
{
    char str[MAXLEN];
    char buf[MAXLEN];
    time_t timep;
    sprintf(chat_log,"./chat_log/%s.txt",(*a).name);
    if((fd=my_open(chat_log,O_RDWR|O_CREAT|O_APPEND,0777)) < 0)
    {
        printf("打开聊天记录失败!");
	exit(1);
    }
    setbuf(stdin,NULL);
    my_strcpy((*a).flag,"all");
    printf("尊敬的%s你好,如需帮助请输入:.help\n",locname);
    while(1)
	{
		memset((*a).msg,0,strlen((*a).msg));
		memset(str,0,strlen(str));
		usleep(100000);
		printf("TO %s:\n",(*a).flag);
		setbuf(stdin,NULL);
		gets(str);
		if(OK == help(str))                      //提示信息  
		{
		    continue;
		}
		my_strcpy((*a).name,locname);
		my_strcpy(buf,(*a).flag);
		cutStr(str,(*a).flag,15,(*a).msg,MAXLEN,'$');    //调用字符切割函数  
		expression((*a).name,(*a).msg);               //表情替换函数 
		common_use_words((*a).msg);                    //常用语使用函数
		if(my_strcmp((*a).flag,"exit") == 0)
		{
		    return FAULT;
		}
		if(my_strcmp((*a).flag,"view") == 0)           
		{
		    my_send(sockfd,a,sizeof((*a)),0);       //请求查看在线用户
	     	    my_strcpy((*a).flag,buf);
		    continue;
		}
		if(my_strcmp((*a).flag,"all") == 0)
		{
		    my_send(sockfd,a,sizeof(*a),0);        
		    continue;
		}
	        if ((my_strcmp((*a).flag,"trans") == 0) && (savefilefd <=0))
		{
    		    if ((my_strcmp((*a).msg,"agree") == 0) && (savefilefd == 0))
		    {
		        char savefilename[MAXLEN];
			my_strcpy((*a).addressee,filefromuser);
			printf("请输入你想保存的文件名:\n");
			do
			{
			    setbuf(stdin,NULL);
			    gets(savefilename);
			    savefilefd = open(savefilename,O_RDWR|O_CREAT|O_EXCL,0777);
			    if(savefilefd == -1)
			    {
			        printf("文件已存在,你重新输入:\n");
			    }
			}while(savefilefd == -1);
			if(savefilefd < 0)
			{
			    printf("接收文件失败!\n");
			    savefilefd = -1;
			}
			else
			{
			    my_strcpy((*a).msg,"agree");
			    my_send(sockfd,a,sizeof(*a),0);
			    printf("文件接收中……\n");
			}
		}
			else
			{
				memset(str,0,strlen(str));
				cutStr((*a).msg,(*a).addressee,20,str,MAXLEN,'$');
				if (str[0] != '\0' && (*a).addressee[0] != '\0')
				{
					char transfileallname[22];
					sprintf(transfileallname,"./%s",str);
					savefilefd = open(str,O_RDWR,0666);
					if(savefilefd < 0)
					{
						printf("打开文件失败!\n");
						savefilefd = -1;
					}
        			else
					{
						memset((*a).msg,0,strlen((*a).msg));
						my_strcpy((*a).msg,str);
						my_send(sockfd,a,sizeof(*a),0);
					}
				}
				else
				{
					my_strcpy((*a).msg,"disagree");
					my_strcpy((*a).name,locname);
					my_strcpy((*a).addressee,filefromuser);
					my_send(sockfd,a,sizeof(*a),0);
				}
			}
			my_strcpy((*a).flag,buf);
			continue;
		}
		if (my_strcmp((*a).flag,"trans") == 0)
		{
			my_strcpy((*a).flag,buf);
		}
		else
		{
			my_strcpy(buf,(*a).flag);
			my_strcpy((*a).addressee,(*a).flag);
			my_strcpy((*a).flag,"personal");
			my_send(sockfd,a,sizeof(*a),0);             //发送私信
			my_strcpy((*a).flag,buf);
			time (&timep);
			memset(str,0,strlen(str));
			sprintf(str,"%s你对 %s 说: %s\n",ctime(&timep),(*a).flag,(*a).msg);
			printf("%s",str);
			my_write(fd,str,strlen(str));              //写入聊天记录文件中
		}
	}
}

/***************************************************
函数名:admin_k
  • 40
    点赞
  • 112
    收藏
    觉得还不错? 一键收藏
  • 100
    评论
Linux C 消息队列聊天室是一种基于Linux系统和C语言编程实现的即时通讯应用。它通过利用Linux系统的消息队列机制来传递消息和实现用户之间的交流。 在消息队列聊天室中,服务器端和客户端分别创建自己的消息队列,并通过消息队列来传递消息。服务器端负责接收客户端的消息,并将其转发给其他在线的客户端。客户端可以发送消息给服务器,也可以接收其他客户端发送的消息。 具体实现时,可以使用系统提供的消息队列函数来创建和操作消息队列。服务器端通过一个守护进程来运行,不断接收客户端的消息并转发。当有客户端连接时,服务器会创建一个子进程来处理与该客户端的通信。客户端通过消息队列与服务器进行通信,并通过标准输入输出流与用户交互。 为了实现聊天室功能,可以设计消息的格式,比如可以使用结构体来定义消息的类型和内容,通过消息类型来区分不同的操作。客户端可以发送登录、注册、聊天等消息类型给服务器,服务器根据不同的消息类型进行相应的处理。 此外,为了保证消息的顺序和可靠性,可以在消息队列中设置消息的优先级,并使用互斥锁来保护共享资源,避免多个客户端同时访问造成的问题。 总之,Linux C 消息队列聊天室是一种基于消息队列机制的即时通讯应用,通过利用Linux系统的特性和C语言编程来实现消息的传递和用户之间的交流。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 100
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值