Linux ubuntu18.04下socket聊天室 私聊 群聊

这个聊天室写出来也有一段时间了
先来几张效果图
进入界面
在这里插入图片描述
登录成功界面
在这里插入图片描述
群聊时三个客户端界面
在这里插入图片描述群聊时服务器打印信息
在这里插入图片描述
mysql数据库里存放的用户信息
在这里插入图片描述
首先要懂几个东西就是 socket网络编程 mysql的增删改查 多线程IO复用的一点皮毛就没了

首先 socket网络编程就下面几个步骤

定义 绑定 设置最大监听数 监听等待连接 收发信息

还有就是mysql 的简单操作

  1. create database 数据库名 ------新建数据库
  2. show create database ------查看数据库定义
  3. drop database 数据库名 ------删除数据库
  4. use 数据库名 ------操作对象切换
  5. create table … ------创建表

然后直接贴代码吧
server.cpp

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/select.h>
#include<string.h>
#include<string>
#include<stdio.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<vector>
#include<memory.h>
#include<pthread.h>
#include<signal.h>
#include<mysql/mysql.h>
#include<stack>
#include<algorithm>
#include<sstream>
using namespace std;
#define SER_PORT 12345
struct user{
	char name[20];
	char sex[3];
	char age[4];
	char phonenumber[12];
	char account[12];
	char password[12];
	int fd_s;
};
vector<user> infos;
struct Sockfd{
	int sockfd_1;
	bool all_chat_flag;
};
vector<Sockfd> sockfdd;
class Database{
public:
	Database();
	~Database();
	void add();
	void Select();
	void conn();
};
MYSQL mysql;
class server:public Database{
public:
	int  all_chat(int fd,char id[12]);                              //群聊  转发给每个套接字
	int  private_chat(int fd,char id[12]);                          //私聊  转发给指定套接字
	int  read_info(int fd);                                                //查看他人信息
	void  deal_client(int &fd);    
	int  check_account(char id[12],char pwd[12]);                   //账号密码验证
	int  add_user(int fd);                                          //新用户注册
private:
	user users;
};
void * papa(void *arg);
void handle_pipe(int sig){
}
int main()
{
	Database bases;
	bases.conn();
	bases.Select();
	struct sigaction sa;
	sa.sa_handler=handle_pipe;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags=0;
	sigaction(SIGPIPE,&sa,NULL);
	int sockfd=socket(AF_INET,SOCK_STREAM,0); //设置套接字
	if(sockfd==-1){
		perror("sockfd error");
		return -1;
	}
	struct sockaddr_in ser_addr;        
	int ret;
	memset(&ser_addr,0,sizeof(ser_addr));
	ser_addr.sin_family=AF_INET;                           //结构体初始化
	ser_addr.sin_port=htons(SER_PORT);
	ser_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
	int opt=1;
	setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
	ret=bind(sockfd,(struct sockaddr *)&ser_addr,sizeof(ser_addr));         //绑定
	if(ret==-1){
		perror("bind error");
		return -1;
	}
	ret=listen(sockfd,128);                                                 //设置最大侦听数
	if(ret==-1){
		perror("listen error");
	}
	int newfd;
	pthread_t id;        
	struct sockaddr_in cli_addr;
	socklen_t len=sizeof(cli_addr);
	while(1){
		memset(&cli_addr,0,sizeof(cli_addr));
		newfd=accept(sockfd,(struct sockaddr *)&cli_addr,&len);           //阻塞等待连接
		if(newfd==-1){
			perror("accept error");
			return -1;
		}
		printf("端口 %d 已加入连接\n",newfd);
		pthread_create(&id,NULL,papa,&newfd);                           //创建线程
		pthread_detach(id);                                             //清除线程
	}
	bases.add();
	return 0;
}

Database::Database(){

}
Database::~Database(){

}
void Database::conn(){
	mysql_init(&mysql);
	if(!mysql_real_connect(&mysql,"localhost","root","root","testdb",12345,NULL,0)){
		cout<<"connect fial\n";
	}
}
void Database::add(){
	bool ret=false;
	string sql;
	for(vector<user>::iterator iter=infos.begin();iter!=infos.end();iter++){
		sql="INSERT INTO client(sex,age,phonenumber,account,password) VALUES(";
		sql.append("'");
		sql.append(iter->sex);
		sql.append("'");
		sql.append(",");
		sql.append("'");
		sql.append(iter->age);
		sql.append("'");
		sql.append(",");
		sql.append("'");
		sql.append(iter->phonenumber);
		sql.append("'");
		sql.append(",");
		sql.append("'");
		sql.append(iter->account);
		sql.append("'");
		sql.append(",");
		sql.append("'");
		sql.append(iter->password);
		sql.append("'");
		sql.append(");");
		ret=mysql_query(&mysql,sql.c_str());
	}
	return;
}

void Database::Select(){
	MYSQL_ROW row;
	user mm;
	MYSQL_FIELD* field =NULL;
	MYSQL_RES* result;
	string sql="SELECT * FROM client";
	mysql_query(&mysql,sql.c_str());
	result=mysql_store_result(&mysql);
	for(int i=0;i<mysql_num_fields(result);i++){
		field=mysql_fetch_field_direct(result,i);
	}
	row=mysql_fetch_row(result);
	while(row!=NULL){
		strcpy(mm.sex,row[0]);
		strcpy(mm.age,row[1]);
		strcpy(mm.phonenumber,row[2]);
		strcpy(mm.account,row[3]);
		strcpy(mm.password,row[4]);
		infos.push_back(mm);
		row=mysql_fetch_row(result);
	}
	return;
}





void * papa(void *arg){
	int fd=*(int * )arg;
	server user_1;
	user_1.deal_client(fd);
}
void server::deal_client(int &fd){                                         //处理客户端
	char recvbuf[1024]={0};
	char recvbuf1[1024]={0};
	char sendbuf[1024]={0};
	int ret;
	while(1){
		memset(sendbuf,0,sizeof(sendbuf));
		strcpy(sendbuf,"\033[31;5;1m[系统消息]:\033[0m\n\033[36;1;4m欢迎加入IKUN粉丝俱乐部 功能如下:\n\t1.登录\n\t2.注册\n\t3.退出\033[0m");    //连接成功欢迎语
		ret=send(fd,sendbuf,strlen(sendbuf),0); 
		if(ret==-1){
			perror("send error");
			return ;
		}
		memset(recvbuf,0,sizeof(recvbuf));
		ret=recv(fd,recvbuf,sizeof(recvbuf),0);
		if(ret==-1){
			perror("recv error");
			return;
		}
		if(strcmp(recvbuf,"1")==0){
			memset(sendbuf,0,sizeof(sendbuf));
			strcpy(sendbuf,"\033[31;5;1m[系统消息:]\033[0m\n\033[36;1m请输入您的账号:\033[0m");
			ret=send(fd,sendbuf,strlen(sendbuf),0);
			if(ret==-1){
				perror("send error");
				return ;
			}
			memset(recvbuf,0,sizeof(recvbuf));
			ret=recv(fd,recvbuf,sizeof(recvbuf),0);
			if(ret==-1){
				perror("recv error");
				return;
			}
			memset(sendbuf,0,sizeof(sendbuf));
			strcpy(sendbuf,"\033[36;1m请输入密码:\033[0m");
			ret=send(fd,sendbuf,strlen(sendbuf),0);
			if(ret==-1){
				perror("send error");
				return ;
			}
			memset(recvbuf1,0,sizeof(recvbuf1));
			ret=recv(fd,recvbuf1,sizeof(recvbuf1),0);
			if(ret==-1){
				perror("recv error");
				return;
			}
			if(check_account(recvbuf,recvbuf1)!=1){                   //登录验证
				memset(sendbuf,0,sizeof(sendbuf));
				strcpy(sendbuf,"\033[31;1;5m[系统消息]:\033[0m\n\033[36;1;4m您的账号或密码不正确\n\033[0m");
				ret=send(fd,sendbuf,strlen(sendbuf),0);
				if(ret==-1){
					perror("send error");
					return ;
				}
			}else{
				memset(sendbuf,0,sizeof(sendbuf));
				strcpy(sendbuf,"\033[31;1;5m[系统消息]:\033[0m\n\033[36;1;4m登录成功 欢迎\n\033[0m");
				ret=send(fd,sendbuf,strlen(sendbuf),0);
				if(ret==-1){
					perror("send error");
					return ;
				}
				for(vector<user>::iterator iter=infos.begin();iter!=infos.end();iter++){
					if(strcmp(iter->account,recvbuf)==0){
						iter->fd_s=fd;
						users=(*iter);
					}
				}
				Sockfd a;
				a.all_chat_flag=false;
				a.sockfd_1=fd;
				sockfdd.push_back(a);
				while(1){
					memset(sendbuf,0,sizeof(sendbuf));
					strcpy(sendbuf,"\033[36;1;4m请输入您的选择:\n\t1.加入群聊 \n\t2.私聊 \n\t3.查看他人信息 \n\t4.退出");
					ret=send(fd,sendbuf,strlen(sendbuf),0);
					if(ret==-1){
						perror("send error");
						return ;
					}
					memset(recvbuf1,0,sizeof(recvbuf1));
					ret=recv(fd,recvbuf1,sizeof(recvbuf1),0);
					if(ret==-1){
						perror("recv error");
						return ;
					}
					if(strcmp(recvbuf1,"1")==0){
						all_chat(fd,recvbuf);
					}
					else if(strcmp(recvbuf1,"2")==0){
						private_chat(fd,recvbuf);
					}
					else if(strcmp(recvbuf1,"3")==0){
						read_info(fd);
					}
					else if(strcmp(recvbuf1,"4")==0){
						break;
					}
					else{
						continue;
					}
				}
			}
		}
		else if(strcmp(recvbuf,"2")==0){
			add_user(fd);
			add();
		}
		else if(strcmp(recvbuf,"3")==0){
			memset(sendbuf,0,sizeof(sendbuf));
			strcpy(sendbuf,"再见!");
			ret=send(fd,sendbuf,strlen(sendbuf),0);
			if(ret==-1){
				perror("send error");
				return ;
			}
			printf("端口 %d 已断开连接\n",fd);
			break;
		}
		else{
			continue;
		}
	}
	close(fd);
}
int server::check_account(char id[12],char pwd[12]){
	for(vector<user>::iterator iter=infos.begin();iter!=infos.end();iter++){
		if((strcmp(id,iter->account)==0)&&(strcmp(pwd,iter->password)==0)){
			return 1;
		}
	}
	return 0;
}
int server::all_chat(int fd,char id[12]){           //群聊
	char sendbuf[1024];
	char recvbuf[1024];
	time_t timep;
	int ret;
	time(&timep);
	strcpy(sendbuf,"\033[31;1;5m[系统消息]:\033[0m\n欢迎加入IKUN大群畅聊\n\t输入quit退出群聊");
	for(vector<Sockfd>::iterator iter=sockfdd.begin();iter!=sockfdd.end();iter++){
		if(fd==iter->sockfd_1){
			iter->all_chat_flag=true;
			break;
		}
	}
	ret=send(fd,sendbuf,sizeof(sendbuf),0);
	if(ret==-1){
		perror("send error");
	}
	while(1){
		memset(recvbuf,0,sizeof(recvbuf));
		int ret;
		ret=recv(fd,recvbuf,sizeof(recvbuf),0);
		if(ret==0)
			break;
		if(strcmp(recvbuf,"quit\0")==0)
		{
			for(vector<Sockfd>::iterator iter=sockfdd.begin();iter!=sockfdd.end();iter++){
				if(fd==iter->sockfd_1){
					iter->all_chat_flag=false;
					break;
				}
			}
			break;
		}
		printf("[%s] 说:%s\n",id,recvbuf);
		for(vector<Sockfd>::iterator iter=sockfdd.begin();iter!=sockfdd.end();iter++){
			if(fd!=iter->sockfd_1&&(iter->all_chat_flag==true)){
				memset(sendbuf,0,sizeof(sendbuf));
				sprintf(sendbuf,"\033[34;1m%s[%s] 说\033[0m: %s",ctime(&timep),id,recvbuf);
				send(iter->sockfd_1,sendbuf,strlen(sendbuf),0);
			}
		}
	}
	return 0;
}
int server::private_chat(int fd,char id[12]){
	int flag=1;
	char recvbuf[1024];
	char sendbuf[1024];
	char str[1024];
	int ret=0;
	time_t timep;
	time(&timep);
	memset(sendbuf,0,sizeof(sendbuf));
	strcpy(sendbuf,"\033[31;1;5m[系统消息]:\033[0m\n\033[36;1;4m请输入需要私聊好友的ID:\n输入quit结束本次聊天");
	send(fd,sendbuf,strlen(sendbuf),0);
	memset(recvbuf,0,sizeof(recvbuf));
	recv(fd,recvbuf,sizeof(recvbuf),0);
	memset(sendbuf,0,sizeof(sendbuf));
	strcpy(sendbuf,"\033[31;1;5m[系统消息]:\033[0m\n\033[36;1;4m您与您的好友已建立私聊通道");
	send(fd,sendbuf,strlen(sendbuf),0);
	strcpy(str,recvbuf);
	for(vector<user>::iterator iter=infos.begin();iter!=infos.end();iter++){
		if(strcmp(iter->account,str)==0){
			ret=iter->fd_s;
		}
	}
	while(1){
		memset(recvbuf,0,sizeof(recvbuf));
		if(strcmp(recvbuf,"quit\0")==0){
			break;
		}
		recv(fd,recvbuf,sizeof(recvbuf),0);
		memset(sendbuf,0,sizeof(sendbuf));
		sprintf(sendbuf,"\033[33;1m[%s] [%s]说\033[0m:%s",ctime(&timep),id,recvbuf);
		printf("%s\n",sendbuf);
		send(ret,sendbuf,strlen(sendbuf),0);
	}
	return 0;
}
int server::read_info(int fd){
	char recvbuf[1024];
	char sendbuf[1024];
	char name_2[20];
	char sex_2[3];
	char age_2[4];
	char phonenumber_2[12];
	char account_2[12];
	bool flag=false;
	system("clear");
	memset(sendbuf,0,sizeof(sendbuf));
	strcpy(sendbuf,"\033[31;1;5m[系统消息]:\033[0m\n\033[36;1;4m请输入您需要查询信息的用户ID:");
	send(fd,sendbuf,strlen(sendbuf),0);
	memset(recvbuf,0,sizeof(recvbuf));
	recv(fd,recvbuf,sizeof(recvbuf),0);
	for(vector<user>::iterator iter=infos.begin();iter!=infos.end();iter++){
		if(strcmp(iter->account,recvbuf)==0){
			flag=true;
			memset(sendbuf,0,sizeof(sendbuf));
			strcpy(sendbuf,"\033[31;1;5m[系统消息]:\033[0m\n\033[36;1;4m您所查询的用户信息如下\n\t\033[0m姓名:");
			send(fd,sendbuf,strlen(sendbuf),0);
			send(fd,iter->name,strlen(iter->name),0);
			memset(sendbuf,0,sizeof(sendbuf));
			strcpy(sendbuf,"\n\t[性别]:");
			send(fd,sendbuf,strlen(sendbuf),0);
			send(fd,iter->sex,strlen(iter->sex),0);
			memset(sendbuf,0,sizeof(sendbuf));
			strcpy(sendbuf,"\n\t[年龄]:");
			send(fd,sendbuf,strlen(sendbuf),0);
			send(fd,iter->age,strlen(iter->age),0);
			memset(sendbuf,0,sizeof(sendbuf));
			strcpy(sendbuf,"\n\t[联系电话]:");
			send(fd,sendbuf,strlen(sendbuf),0);
			send(fd,iter->phonenumber,strlen(iter->phonenumber),0);
			memset(sendbuf,0,sizeof(sendbuf));
			strcpy(sendbuf,"\n\t[账户号码]:");
			send(fd,sendbuf,strlen(sendbuf),0);
			send(fd,iter->account,strlen(iter->account),0);
			send(fd,"\n",1,0);
		}
	}
	if(!flag){
		memset(sendbuf,0,sizeof(sendbuf));
		strcpy(sendbuf,"\033[31;1;5m[系统消息]:\033[0m\n未找到您查询的用户 即将返回上一页\n");
		send(fd,sendbuf,strlen(sendbuf),0);
	}
	return 0;
}
int server::add_user(int fd){
	int leap=0;
	char str[256];
	char str1[256];
	user adds;
	memset(str,0,sizeof(str));
	memset(str1,0,sizeof(str1));
	strcpy(str,"\033[31;1;5m[系统消息]:\033[0m\n\033[36;1;4m请输入11位以下账号进行注册:");
	send(fd,str,strlen(str),0);
	memset(str,0,sizeof(str));
	recv(fd,str,sizeof(str),0);
	strcpy(str1,str);
	for(vector<user>::iterator iter=infos.begin();iter!=infos.end();iter++){
		if(strcmp(str,iter->account)==0){
			memset(str,0,sizeof(str));
			strcpy(str,"\033[31;1;5m[系统消息]\033[0m:\n账号重复\n");
			send(fd,str,strlen(str),0);
			return -1;
		}
	}
	strcpy(adds.account,str1);
	memset(str,0,sizeof(str));
	strcpy(str,"请输入密码:");
	send(fd,str,strlen(str),0);
	memset(str,0,sizeof(str));
	recv(fd,str,sizeof(str),0);
	strcpy(adds.password,str);
	memset(str,0,sizeof(str));
	strcpy(str,"请设置你的昵称:");
	send(fd,str,strlen(str),0);
	memset(str,0,sizeof(str));
	recv(fd,str,sizeof(str),0);
	strcpy(adds.name,str);
	memset(str,0,sizeof(str));
	strcpy(str,"请输入你的性别:");
	send(fd,str,strlen(str),0);
	memset(str,0,sizeof(str));
	recv(fd,str,sizeof(str),0);
	strcpy(adds.sex,str);
	memset(str,0,sizeof(str));
	strcpy(str,"请输入你的年龄:");
	send(fd,str,strlen(str),0);
	memset(str,0,sizeof(str));
	recv(fd,str,sizeof(str),0);
	strcpy(adds.age,str);
	memset(str,0,sizeof(str));
	strcpy(str,"请输入你的联系电话:");
	send(fd,str,strlen(str),0);
	memset(str,0,sizeof(str));
	recv(fd,str,sizeof(str),0);
	strcpy(adds.phonenumber,str);
	infos.push_back(adds);
	return 0;
}

client.cpp

#include<iostream>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include<sys/time.h>
#include<arpa/inet.h>
#include<unistd.h>
using namespace std;
#define SER_PORT 12345
int main(){
	int sockfd=socket(AF_INET,SOCK_STREAM,0);
	if(sockfd==-1){
		perror("socket erro");
		exit(1);
	}
	int maxfd=-1;
	fd_set rfds;
	char buffer[1025];
	int retval;
	struct timeval time;
	struct sockaddr_in addr;
	int len;
	bzero(&addr,sizeof(addr));
	addr.sin_family=AF_INET;
	addr.sin_port=htons(SER_PORT);
	addr.sin_addr.s_addr=inet_addr("127.0.0.1");
	
	connect(sockfd,(struct sockaddr *)&addr,sizeof(addr));
	while(1){
		FD_ZERO(&rfds);
		FD_SET(0,&rfds);
		maxfd=0;
		FD_SET(sockfd,&rfds);
		if(sockfd>maxfd){
			maxfd=sockfd;
		}
		time.tv_sec=1;
		time.tv_usec=0;
		retval=select(maxfd+1,&rfds,NULL,NULL,&time);
		if(retval==-1){
			perror("select error");
			break;
		}else if(retval==0){
			continue;
		}else{
			if(FD_ISSET(sockfd,&rfds)){
				bzero(buffer,1025);
				len=recv(sockfd,buffer,1024,0);
				if(len>0){
					cout<<buffer<<endl;
				}else{
					if(len<0){
						perror("recv error");
					}
					break;
				}

			}
			if(FD_ISSET(0,&rfds)){
				bzero(buffer,1025);
				fgets(buffer,1024,stdin);
				len=send(sockfd,buffer,strlen(buffer)-1,0);
				if(len<0){
					perror("send error");
				}
			}
		}

	}
	close(sockfd);
	return 0;


}

完事。。。

  • 3
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值