基于Golang的服务器与基于Qt的跨平台客户端进行通信。
1.安装Golang
下载链接
根据你的PC情况安装对应版本,这里我选择的是window版本
2.配置Go代理
go env -w GOPROXY=https://goproxy.cn,direct
3.设计聊天服务器协议
syntax = "proto3";
package httpapi;
/*
*@brief:业务逻辑http服务器:
@release:
*用户的uuid:用于查找该用户的信息
*用户的token:用户所有上传操作的验证
*资源的token:用于直接下载
@1.负责用户头像下载,上传
-下载时只需要资源token
-上传时需要 用户校验token + 原资源token
@2.负责用户信息下载,上传
-下载时需要用户对应token-
-上传时需要
*/
enum SystemNotificationType//系统通知类型
{
NotifAddFriend = 0;//有用户添加你为好友
OtherClientLogin = 1;
}
message SystemNotificationEvent {
SystemNotificationType type = 1;
string content = 2;
}
message None {
}
/*****@上传/下载文件@*****/
enum LogicFileType{
UserAvatar = 0;//头像
}
message SendFileInfoRequest {
int32 filesize = 1;//文件大小
string fileName = 2;//文件姓名
string fileUuid = 3;//唯一标识符
int32 fileBlockNum = 4;//如果不分片就为1
}
// 大文件要先发送SendFileInfoRequest,然后服务器响应SendFileInfoResponse
// 然后客户端发送UpLoadFileRequest,服务器收到后返回UpLoadFileResponse
message SendFileInfoResponse {
int32 filesize = 1;//文件大小
string fileName = 2;//文件姓名
string fileUuid = 3;//唯一标识符
int32 fileBlockNum = 4;//如果不分片就为1
}
message SendFileRequest {
string fileUuid = 1;//唯一标识符
string to = 2;
int32 fileIndex = 3;
bytes data = 4;
}
//上传文件需要指明用户 ->用户的uuid
message SendFileResponse {//上传文件
string fileUuid = 1;//唯一标识符
string res = 2;//成功上传返回token 失败返回0
}
//下载文件部分需指明用户
message DownLoadFileRequest {
string fileUuid = 1;
}
message DownLoadFileResponse {
string fileUuid = 1;
int64 totalSize = 2;
uint64 seq = 3;
bytes content = 4;
}
message UpLoadFileRequest {
string fileName = 1;
int64 totalSize = 2;
uint64 seq = 3;
bytes content = 4;
}
/********************/
/*****@登陆/注册/登出@*****/
/*
there is only list sub two parts and more
*kPassWordError | kNeedVerifCode
one way:1 index 1
the onther way: 0x1 | xx or 0x4 | xx
*/
enum LoginResult {
LoginInvild = 0;
PassWordError = 1;//passwd error
LoginSuccess = 2;//login success
AlreadLogin = 3;//client alread login in anther place
AccountFreezing = 4;// account freezing now
PassWordErrorManyTimes = 5;//passwd error too many times
AccountNotExist = 6;//client not exist
NeedVerifCode = 7;//verifCode client need verifcode and post data again
//unkown error,call the client try it again
}
enum RegisterResult {
RegisterInvild = 0;
AccountExist = 1;
RegisterSuccess = 2;
RegusterFreezing = 3;
}
message BasicUserInfo{
string name = 1;
string account = 2;
}
message UserInfo {
string uuid = 1;
string name = 2;
string phone = 3;
uint32 sex = 4;
string email = 5;
string description = 6;
string UserAvatar = 7;
bytes UserAvatarContent = 8;//头像缩略图
}
message UserLoginRequest {
string userAccount = 1;
string userPassword = 2;
string device = 3;//当前设备
string version = 4;//客户端版本
}
message UserLoginResponse {
string token = 1;//token
LoginResult result = 2;//登陆结果
UserInfo ownInfo = 3;//个人资料
}
enum RegisterType {//注册类型
Phone = 0;
Email = 1;
}
message UserRegisterRequest {
RegisterType type = 1;//注册类型
BasicUserInfo userInfo = 2; //注册信息
string userPassword = 3;//用户密码
}
message UserRegisterResponse {
RegisterResult result = 1;
string uuid = 2;//注册结果 成功为uuid 失败为0
}
message UserLoginOutRequest {
string userUuid = 1;//用户uuid
string userToken = 2;//用户token
string device = 3;//当前设备
}
message UserLoginOutResponse {
string result = 1;//登出结果
}
/********************/
/*****@个人信息@*****/
//拉取个人用户信息
message PullUserInfoRequest {
string userAccount = 1;
uint64 updateTime = 2;
}
message PullUserInfoResponse {
bool needUpdate = 1;
UserInfo userInfo = 2;
}
message PushUserInfoRequest {
string userAccount = 1;
string token = 2;
uint64 updateTime = 3;
UserInfo userInfo = 4;
}
/********************/
enum DeviceType {
Unknown = 0;
Android = 1;
IOS = 2;
MacOS = 3;
WatchOs = 4;
Windows = 5;
}
enum NetType {
_2G = 0;
_3G = 1;
_4G = 2;
_5G = 3;
Wifi = 4;
}
/*****@friend信息@*****/
message FriendInfo{
UserInfo userInfo = 1;
DeviceType decviceType = 2;
bool online = 3;
}
message FriendInfoItem{
string friendUuid = 1;
string alias = 2;
string group = 3;
uint64 updateTime = 4;
}
message UserListResponse {
//repeated c++ FriendInfo[]
repeated FriendInfo friendInfos = 1;
}
message PullFriendsInfo{
repeated FriendInfoItem friends = 1;
}
/********************/
//operation must be take token and uuid
/*****@find friend/add friend/delete friend信息@*****/
enum AddUserResponseType {
AddUserInvild = 0;
AddUserNotExist = 1;
AddUserRefuse = 2;
AddUserSuccess = 3;
AlareadAddUser = 4;
}
message AddFriendMsg {
enum AddFriendStatus {
NotAddUser = 0;
AddUserSuccess = 1;
RefuseAddUser = 2;
AlareadAddUser = 3;
}
UserInfo userInfo = 1;
AddFriendStatus status = 2;
}
message UserEvent {
enum UserEventType {
AddUserRequest = 0;
AddUserResponse = 1;
DelFriendRequest = 3;
FindUserRequest = 4;
FindUserResponse = 5;
ChangeUserRequest = 6;
ChangeUserResponse = 7;
CheckUserOnlineRequest = 8;
CheckUserOnlineResponse = 9;
}
UserEventType type = 1;
string from = 2;
string eventContent = 3; // json
UserInfo userInfo = 4;//如果有修改就返回该字段
}
/********************/
// 聊天
message ChatMessage {
enum ContentType {
Unknown = 0;
Text = 1;
Image = 2;
Video = 3;
Audio = 4;
File = 5;
};
uint64 timestamp = 3;
bytes content = 4;
ContentType type = 5;
string from = 6;
string to = 7;
string filelocalPath = 8;
string fileUuid = 9;
}
message ChatMessageRequest {
string seq = 1;
uint64 totalBlock = 2;// == 1 没有分片
uint64 splitSeq = 3;// == 0 没有分片
ChatMessage message = 4;
}
message ChatMessageResponse {
string seq = 1;
}
//golang server
//c++ client
service HttpApi {
rpc DownLoadFile(DownLoadFileRequest) returns (stream DownLoadFileResponse) {}
rpc UpLoadFile(UpLoadFileRequest) returns (None) {}
rpc Login(UserLoginRequest) returns (UserLoginResponse) {}
rpc Register(UserRegisterRequest) returns (UserRegisterResponse) {}
rpc UserList(None) returns (UserListResponse) {}
rpc SendChatMessage(stream ChatMessageRequest) returns (stream ChatMessageResponse) {}
rpc ChatMessageLoop(stream None) returns (stream ChatMessageRequest) {}
rpc SendFile(stream SendFileRequest) returns (SendFileResponse) {}
rpc sendFileInfo(SendFileInfoRequest) returns (SendFileInfoResponse) {}
rpc UserEventLoop(stream UserEvent) returns (stream UserEvent) {}
rpc PullUserEvent(UserEvent) returns (None) {}
rpc SystemNotificationEventLoop(None) returns (stream SystemNotificationEvent) {}
}
4.使用proto工具生成api
protoc --go_out=plugins=grpc:. httpapi.proto
5.使用脚本创建自定义证书
- 适用于localhost的服务器
#!/bin/sh
echo Generate CA key:
openssl genrsa -passout pass:1111 -des3 -out ca.key 2048
echo Generate CA certificate:
openssl req -passin pass:1111 -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/C=CN/ST=FuJian/L=XiaMen/O=YaXon/OU=gRPC/CN=localhost"
echo Generate server key:
openssl genrsa -passout pass:1111 -des3 -out server_privatekey.pem 2048
echo Generate server signing request:
openssl req -passin pass:1111 -new -key server_privatekey.pem -out server_csr.pem -subj "/C=CN/ST=FuJian/L=XiaMen/O=YaXon/OU=gRPC/CN=localhost"
echo Self-sign server certificate:
openssl x509 -req -passin pass:1111 -days 3650 -in server_csr.pem -CA ca.crt -CAkey ca.key -CAcreateserial -out server_self_signed_crt.pem
echo Remove passphrase from server key:
openssl rsa -passin pass:1111 -in server_privatekey.pem -out server_privatekey.pem
echo Generate client key
openssl genrsa -passout pass:1111 -des3 -out client_privatekey.pem 2048
echo Generate client signing request:
openssl req -passin pass:1111 -new -key client_privatekey.pem -out client_csr.pem -subj "/C=CN/ST=FuJian/L=XiaMen/O=YaXon/OU=gRPC/CN=localhost"
echo Self-sign client certificate:
openssl x509 -passin pass:1111 -req -days 3650 -in client_csr.pem -CA ca.crt -CAkey ca.key -CAcreateserial -out client_self_signed_crt.pem
echo Remove passphrase from client key:
openssl rsa -passin pass:1111 -in client_privatekey.pem -out client_privatekey.pem