这个聊天室写出来也有一段时间了
先来几张效果图
进入界面
登录成功界面
群聊时三个客户端界面
群聊时服务器打印信息:
mysql数据库里存放的用户信息:
首先要懂几个东西就是 socket网络编程 mysql的增删改查 多线程和IO复用的一点皮毛就没了
首先 socket网络编程就下面几个步骤
定义 绑定 设置最大监听数 监听等待连接 收发信息
还有就是mysql 的简单操作
- create database 数据库名 ------新建数据库
- show create database ------查看数据库定义
- drop database 数据库名 ------删除数据库
- use 数据库名 ------操作对象切换
- 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;
}
完事。。。