C++搭建集群聊天室,java多线程面试总结

client.cpp


#include “json.hpp”

#include

#include

#include

#include

#include

#include

#include <unordered_map>

#include

using namespace std;

using json = nlohmann::json;

#include <unistd.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <semaphore.h>

#include

#include “group.hpp”

#include “user.hpp”

#include “public.hpp”

// 记录当前系统登录的用户信息

User g_currentUser;

// 记录当前登录用户的好友列表信息

vector g_currentUserFriendList;

// 记录当前登录用户的群组列表信息

vector g_currentUserGroupList;

// 控制主菜单页面程序

bool isMainMenuRunning = false;

// 用于读写线程之间的通信

sem_t rwsem;

// 记录登录状态

atomic_bool g_isLoginSuccess{false};

// 接收线程

void readTaskHandler(int clientfd);

// 获取系统时间(聊天信息需要添加时间信息)

string getCurrentTime();

// 主聊天页面程序

void mainMenu(int);

// 显示当前登录成功用户的基本信息

void showCurrentUserData();

// 聊天客户端程序实现,main线程用作发送线程,子线程用作接收线程

int main(int argc, char **argv)

{

if (argc < 3)

{

cerr << “command invalid! example: ./ChatClient 127.0.0.1 6000” << endl;

exit(-1);

}

// 解析通过命令行参数传递的ip和port

char *ip = argv[1];

uint16_t port = atoi(argv[2]);

// 创建client端的socket

int clientfd = socket(AF_INET, SOCK_STREAM, 0);

if (-1 == clientfd)

{

cerr << “socket create error” << endl;

exit(-1);

}

// 填写client需要连接的server信息ip+port

sockaddr_in server;

memset(&server, 0, sizeof(sockaddr_in));

server.sin_family = AF_INET;

server.sin_port = htons(port);

server.sin_addr.s_addr = inet_addr(ip);

// client和server进行连接

if (-1 == connect(clientfd, (sockaddr *)&server, sizeof(sockaddr_in)))

{

cerr << “connect server error” << endl;

close(clientfd);

exit(-1);

}

// 初始化读写线程通信用的信号量

sem_init(&rwsem, 0, 0);

// 连接服务器成功,启动接收子线程

// 这种操作方法以前倒是没有用过

std::thread readTask(readTaskHandler, clientfd); // pthread_create

readTask.detach(); // pthread_detach

// main线程用于接收用户输入,负责发送数据

for (;😉

{

// 显示首页面菜单 登录、注册、退出

cout << “========================” << endl;

cout << “1. login” << endl;

cout << “2. register” << endl;

cout << “3. quit” << endl;

cout << “========================” << endl;

cout << “choice:”;

int choice = 0;

cin >> choice;

cin.get(); // 读掉缓冲区残留的回车

switch (choice)

{

case 1: // login业务

{

int id = 0;

char pwd[50] = {0};

cout << “userid:”;

cin >> id;

cin.get(); // 读掉缓冲区残留的回车

cout << “userpassword:”;

cin.getline(pwd, 50);

json js;

js[“msgid”] = LOGIN_TYPE;

js[“id”] = id;

js[“password”] = pwd;

string request = js.dump();

g_isLoginSuccess = false;

int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);

if (len == -1)

{

cerr << “send login msg error:” << request << endl;

}

sem_wait(&rwsem); // 等待信号量,由子线程处理完登录的响应消息后,通知这里

if (g_isLoginSuccess)

{

// 进入聊天主菜单页面

isMainMenuRunning = true;

mainMenu(clientfd);

}

}

break;

case 2: // register业务

{

char name[50] = {0};

char pwd[50] = {0};

cout << “username:”;

cin.getline(name, 50);

cout << “userpassword:”;

cin.getline(pwd, 50);

json js;

js[“msgid”] = REG_TYPE;

js[“name”] = name;

js[“password”] = pwd;

string request = js.dump();

int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);

if (len == -1)

{

cerr << “send reg msg error:” << request << endl;

}

sem_wait(&rwsem); // 等待信号量,子线程处理完注册消息会通知

}

break;

case 3: // quit业务

close(clientfd);

sem_destroy(&rwsem);

exit(0);

default:

cerr << “invalid input!” << endl;

break;

}

}

return 0;

}

// 处理注册的响应逻辑

void doRegResponse(json &responsejs)

{

if (0 != responsejs[“errno”].get()) // 注册失败

{

cerr << “name is already exist, register error!” << endl;

}

else // 注册成功

{

cout << "name register success, userid is " << responsejs[“id”]

<< “, do not forget it!” << endl;

}

}

// 处理登录的响应逻辑

void doLoginResponse(json &responsejs)

{

if (0 != responsejs[“errno”].get()) // 登录失败

{

cerr << responsejs[“errmsg”] << endl;

g_isLoginSuccess = false;

}

else // 登录成功

{

// 记录当前用户的id和name

g_currentUser.setID(responsejs[“id”].get());

g_currentUser.setname(responsejs[“name”]);

// 记录当前用户的好友列表信息

if (responsejs.contains(“friends”)) //如果有,贸然解析有崩溃的风险,JSON模块可脆弱

{

// 初始化

g_currentUserFriendList.clear();

vector vec = responsejs[“friends”];

for (string &str : vec)

{

json js = json::parse(str);

User user;

user.setID(js[“id”].get());

user.setname(js[“name”]);

user.setstate(js[“state”]);

g_currentUserFriendList.push_back(user);

}

}

// 记录当前用户的群组列表信息

if (responsejs.contains(“groups”))

{

// 初始化

g_currentUserGroupList.clear();

vector vec1 = responsejs[“groups”];

for (string &groupstr : vec1)

{

json grpjs = json::parse(groupstr);

Group group;

group.setId(grpjs[“id”].get());

group.setName(grpjs[“groupname”]);

group.setDesc(grpjs[“groupdesc”]);

vector vec2 = grpjs[“users”];

for (string &userstr : vec2)

{

GroupUser user;

json js = json::parse(userstr);

user.setID(js[“id”].get());

user.setname(js[“name”]);

user.setstate(js[“state”]);

user.setRole(js[“role”]);

group.getUsers().push_back(user);

}

g_currentUserGroupList.push_back(group);

}

}

// 显示登录用户的基本信息

showCurrentUserData();

// 显示当前用户的离线消息 个人聊天信息或者群组消息

if (responsejs.contains(“offlinemsg”))

{

vector vec = responsejs[“offlinemsg”];

for (string &str : vec)

{

json js = json::parse(str);

// time + [id] + name + " said: " + xxx

if (ONE_CHAT_MSG == js[“msgid”].get())

{

cout << js[“time”].get() << " [" << js[“id”] << “]” << js[“name”].get()

<< " said: " << js[“msg”].get() << endl;

}

else

{

cout << “群消息[” << js[“groupid”] << “]:” << js[“time”].get() << " [" << js[“id”] << “]” << js[“name”].get()

<< " said: " << js[“msg”].get() << endl;

}

}

}

g_isLoginSuccess = true;

}

}

// 子线程 - 接收线程

void readTaskHandler(int clientfd)

{

for (;😉

{

char buffer[1024] = {0};

int len = recv(clientfd, buffer, 1024, 0); // 阻塞了

if (-1 == len || 0 == len)

{

close(clientfd);

exit(-1);

}

// 接收ChatServer转发的数据,反序列化生成json数据对象

json js = json::parse(buffer);

int msgtype = js[“msgid”].get();

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后

做任何事情都要用心,要非常关注细节。看起来不起眼的、繁琐的工作做透了会有意想不到的价值。
当然要想成为一个技术大牛也需要一定的思想格局,思想决定未来你要往哪个方向去走, 建议多看一些人生规划方面的书籍,多学习名人的思想格局,未来你的路会走的更远。

更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务

]
[外链图片转存中…(img-B57r1IUX-1710688601406)]
[外链图片转存中…(img-P07ZunZk-1710688601406)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-23qVSp01-1710688601407)]

最后

做任何事情都要用心,要非常关注细节。看起来不起眼的、繁琐的工作做透了会有意想不到的价值。
当然要想成为一个技术大牛也需要一定的思想格局,思想决定未来你要往哪个方向去走, 建议多看一些人生规划方面的书籍,多学习名人的思想格局,未来你的路会走的更远。

更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务

[外链图片转存中…(img-Eqq6o596-1710688601407)]

[外链图片转存中…(img-7S2qj4B6-1710688601408)]

[外链图片转存中…(img-n9MlJiKL-1710688601408)]

[外链图片转存中…(img-pmYamGnL-1710688601409)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值