這個聊天室寫出來也有一段時間了
先來幾張效果圖
進入界面
登錄成功界面
群聊時三個客戶端界面
群聊時服務器打印信息:
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;}
完事。。。
總結
以上是生活随笔為你收集整理的Linux ubuntu18.04下socket聊天室 私聊 群聊的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。