使用线程实现QQ聊天

it2023-11-27  71

使用线程实现QQ聊天

     server端代码:

#include<iostream> #include<unistd.h> #include<stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include<string.h> #include<arpa/inet.h> #include <pthread.h> #include<vector> #define SERVER_PORT 9527 //port #define BACKLOG 10 //同时允许多少个客户端跟server建立连接 #define GROUP_CHAT 0 //群聊 #define PRIVATE_CHAT 1 //私聊 #define OFF_LINE 2 //下线 #define ON_LINE 3 //上线 using namespace std; typedef struct //定义一个聊天结构体 { int user_id; //用户id int type; char name[16]; //用户名 char message[200]; //消息内容 char to_the_other_one[20]; //要私聊的用户 }STU; typedef struct { int accept_fd; //保存客户端的accept_fd char user_name[16]; //姓名 char message[200]; //消息内容 }CLIENT_ACCEPT_FD; vector<CLIENT_ACCEPT_FD > client_info;//容器中存放客户端信息 //线程处理函数 void* thread_fun(void* accept_fd) { int r_size; size_t w_size; int tmp_fd = *((int*)accept_fd);// accept_fd 传过来,用这个accept_fd 实现群发功能 STU user0;//声明用户1 CLIENT_ACCEPT_FD Client;//保存着accept_fd的聊天结构体 //对这两个结构体初始化 bzero(&user0, sizeof(user0)); bzero(&Client, sizeof(Client)); Client.accept_fd = tmp_fd; client_info.push_back(Client);//把客户端信息加入容器中 //cout << "容器中的大小是" << client_info.size() << endl; while (1) { //读客户端发过来的数据 r_size = read(tmp_fd, &user0, sizeof(user0)); //r_size >0 有读到数据 <0 错误 == 0 有客户端退出 if (r_size > 0) { //cout << "姓名:" << user0.name << endl; //cout << "消息体:" << user0.message << endl; strcpy(Client.user_name, user0.name); strcpy(Client.message, user0.message); cout << "姓名:" << Client.user_name << "消息" << Client.message << endl; //cout << "服务器收到的类型是" << user0.type << endl; if (user0.type == GROUP_CHAT) //是群聊 { //遍历容器 回发消息给每个客户端 for (int i = 0; i < client_info.size(); i++) { w_size = write(client_info[i].accept_fd, &user0, sizeof(user0)); } } if (user0.type == PRIVATE_CHAT) //是私聊 { for (int i = 0; i < client_info.size(); i++) { if (client_info[i].user_name == user0.to_the_other_one) { w_size = write(client_info[i].accept_fd, &user0, sizeof(user0)); break; } } } } else if (r_size == 0)//客户端下线 { vector<CLIENT_ACCEPT_FD>::iterator it; cout << "没下线前的" << client_info.size() << endl; for (it = client_info.begin(); it != client_info.end(); it++) { //找到下线用户的accept_fd 把他从容器中移除 if (it->accept_fd == tmp_fd) { user0.type = OFF_LINE; client_info.erase(it); break; } } cout << "下线后的" << client_info.size() << endl; for (int i = 0; i < client_info.size(); i++) { w_size = write(client_info[i].accept_fd, &user0, sizeof(user0)); } return NULL; } else if (r_size < 0) { perror("read error"); return NULL; } } } int main() { int ret = 0; int accept_fd; pthread_t thread_id; // creat socket int socket_fd;//套接字描述符 socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) { perror("socket error"); return -1; } // 设置端口复用 int opt = 1;//开启端口复用 setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //bind struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); ret = bind(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (ret < 0) { perror("bind error"); return -1; } //listen ret = listen(socket_fd, BACKLOG); while (1) { cout << "wait connect ..." << endl; accept_fd = accept(socket_fd, NULL, NULL); cout << "connected !!!" << endl; if (accept_fd == -1) { perror("accept error"); return -1; } ret = pthread_create(&thread_id, NULL, thread_fun, &accept_fd);//创建线程 if (ret != 0) { perror("pthread_create error"); return -1; } } return 0; }

   client 端代码:

#include<iostream> #include<stdio.h> #include<unistd.h> #include<arpa/inet.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <string.h> #define SERVER_PORT 9527 #define SERVER_IP "192.168.75.128" #define GROUP_CHAT 0 //群聊 #define PRIVATE_CHAT 1 //私聊 #define OFF_LINE 2 //下线 #define ON_LINE 3 //上线 using namespace std; typedef struct //定义一个聊天结构体 { int user_id; //用户id int type; char name[16]; //用户名 char message[200]; //消息内容 char to_the_other_one[20]; //要私聊的用户 }STU; int main() { //客户端代码 /* 思路:socket 读用专门的进程来实现。从客户端获取聊天内容用另一个进程去做 */ pid_t pid; int r_size = 0; //socket int client_fd; int ret = 0; client_fd = socket(AF_INET, SOCK_STREAM, 0); if (client_fd == -1) { perror("socket error"); return -1; } //connect struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(SERVER_PORT); addr.sin_addr.s_addr = inet_addr(SERVER_IP); ret = connect(client_fd, (const struct sockaddr*) &addr,sizeof(addr)); //聊天结构体初始化 STU chat1; char name[16] = { 0 }; char other_name[16] = { 0 }; char buffer[100] = { 0 }; int m_type; bzero(&chat1,sizeof(chat1)); cout << "请输入你的姓名:" << endl; cin >> name; cout << "请输入聊天类型 0:群聊 1:私聊 " << endl; cin >> m_type; cout << "类型是" << m_type << endl; if (m_type == 1) { cout << "请输入你要私聊的用户名" << endl; cin >>other_name; } pid = fork(); if (pid > 0)//父进程 { while (fgets(buffer, sizeof(buffer), stdin) != NULL) { strcpy(chat1.to_the_other_one, other_name);//对方名字 strcpy(chat1.name, name); strcpy(chat1.message, buffer);//通过buffer 把消息传递到结构体的message中 chat1.type = m_type;//类型传递 write(client_fd, &chat1, sizeof(chat1)); memset(&chat1, 0, sizeof(chat1)); memset(buffer, 0, sizeof(buffer)); } } else if (pid == 0)//子进程 { //读取数据 STU chat2; bzero(&chat2, sizeof(chat2)); int tmp = 0; while (r_size = (read(client_fd, &chat2, sizeof(chat2))) > 0) { if (strcmp(chat2.name, name) != 0) { cout << chat2.name << ": " << chat2.message << endl; } if (chat2.type == OFF_LINE)//下线 { cout << chat2.name << "下线了" << endl; } } } return 0; }

   运行效果:

最新回复(0)