s o c k e t socket socket入门:传送门
p r o t o b u f protobuf protobuf官方文档:传送门
e p o l l epoll epoll入门教程:传送门
客户端思想:注册,登录,登录成功可以听消息
服务器思想:
d b . p r o t o db.proto db.proto
syntax = "proto3";
package user;
message Person {
string name = 1;
string passwd = 2;
string x = 3;
string y =4;
}
message AddressBook {
repeated Person people = 1;
}
命令行
protoc --cpp_out=./ db.proto
d b s e r v e r . c p p dbserver.cpp dbserver.cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include<sys/types.h>
#include<sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <bits/stdc++.h>
#include <fstream>
#include <errno.h>
#include <fcntl.h>
#include "db.pb.h"
using namespace std;
using namespace user;
const int FD_SIZE = 1000;
const int EPOLL_EVENTS = 1000;
const int BUFFER_SIZE = 1505;
struct Fd_msg{
int totalLength;
char* totalBytes;
};
char bytes[BUFFER_SIZE];
AddressBook clients_book;
set<int> connected_fd;
unordered_map<int, Fd_msg> map_fd_msg;
Person peo;
char flag[1];
char* message;
int len;
auto intToChar4(int i)
{
auto result = new char[4];
result[0] = (i >> 24 & 0xFF);
result[1] = (i >> 16 & 0xFF);
result[2] = (i >> 8 & 0xFF);
result[3] = (i & 0xFF);
return result;
}
auto intToChar(int i)
{
char result = (i & 0xFF);
return result;
}
auto char4ToInt(char* bytes)
{
int num = bytes[3] & 0xFF;
num |= ((bytes[2] << 8) & 0xFF00);
num |= ((bytes[1] << 16) & 0xFF0000);
num |= ((bytes[0] << 24) & 0xFF000000);
return num;
}
void add_epoll_event(int epollfd, int fd, int state){
struct epoll_event ev;
ev.events = state;
ev.data.fd = fd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
}
void delete_epoll_event(int epollfd,int fd,int state){
struct epoll_event ev;
ev.events = state;
ev.data.fd = fd;
epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&ev);
}
void modify_event(int epollfd,int fd,int state){
struct epoll_event ev;
ev.events = state;
ev.data.fd = fd;
epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&ev);
}
bool existt(Person peo)
{
for(int i = 0; i < clients_book.people_size(); i++){
const Person& person = clients_book.people(i);
if (person.name() == peo.name() && person.passwd() == peo.passwd())
{
return true;
}
}
return false;
}
void updatetheclient(Person* person, Person peo)
{
for(int i = 0; i < clients_book.people_size(); i++){
Person person = clients_book.people(i);
if (person.name() == peo.name() && person.passwd() == peo.passwd())
{
person.set_x(peo.x());
person.set_y(peo.y());
return ;
}
}
}
void PromptForclient(Person* person, Person peo) {
string name, passwd;
person->set_name(peo.name());
person->set_passwd(peo.passwd());
person->set_x(peo.x());
person->set_y(peo.y());
cout << "has added " << peo.name() << " " << peo.passwd() << " " << peo.x() << " " << peo.y() <<endl;
}
void handle_accept(int epollfd, int serv_sock)
{
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
int flags = fcntl(clnt_sock,F_GETFL,0);
fcntl(clnt_sock,F_SETFL,flags| O_NONBLOCK);
add_epoll_event(epollfd, clnt_sock, EPOLLIN);
Fd_msg* fd_msg = (Fd_msg*)malloc(sizeof(Fd_msg));
fd_msg->totalLength = 0;
fd_msg->totalBytes = new char(0);
map_fd_msg[clnt_sock] = *fd_msg;
}
void pack()
{
len = peo.ByteSizeLong();
char* messagebody = new char[len];
peo.SerializeToArray(messagebody, len);
char* lengthBytes = new char(4);
lengthBytes = intToChar4(len + 1);
char messageid;
messageid = intToChar(1);
message = new char(len + 5);
for (int i = 0; i < 4; i++) {
message[i] = lengthBytes[i];
}
message[4] = messageid;
for (int i = 5; i < 5 + len; i++) {
message[i] = messagebody[i - 5];
}
}
void boardcast(int epollfd, int now_fd)
{
for (auto fd : connected_fd) {
modify_event(epollfd, fd, EPOLLOUT);
}
}
void handle_read(int epollfd, int fd)
{
auto iter = map_fd_msg.find(fd);
Fd_msg* fd_msg = &iter->second;
while ((len = read(fd, bytes, 1505)) != -1) {
int tmpLength = fd_msg->totalLength;
fd_msg->totalLength += len;
char* tmpBytes = new char[tmpLength];
for (int i = 0; i < tmpLength; i++) {
tmpBytes[i] = fd_msg->totalBytes[i];
}
fd_msg->totalBytes = new char[fd_msg->totalLength];
for (int i = 0; i < tmpLength; i++) {
fd_msg->totalBytes[i] = tmpBytes[i];
}
for (int i = tmpLength; i < fd_msg->totalLength; i++) {
fd_msg->totalBytes[i] = bytes[i - tmpLength];
}
while (fd_msg->totalLength >= 5) {
char *lengthBytes = new char[4];
for (int i = 0; i < 4; i++) {
lengthBytes[i] = fd_msg->totalBytes[i];
}
int contentLength = char4ToInt(lengthBytes) - 1;
char messageid = fd_msg->totalBytes[4];
int f = messageid & 0xFF;
if (fd_msg->totalLength < contentLength + 5) {
break;
}
char* contentBytes = new char[contentLength];
for (int i = 0; i < contentLength; i++) {
contentBytes[i] = fd_msg->totalBytes[i + 5];
}
peo.ParseFromArray(contentBytes, contentLength);
if (f == 1) {
PromptForclient(clients_book.add_people(), peo);
} else if (f == 2) {
flag[0] = '1';
if (existt(peo) == false) {
flag[0] = '0';
write(fd, flag, 1);
} else {
connected_fd.insert(fd);
write(fd, flag, 1);
boardcast(epollfd, fd);
}
} else if (f == 3) {
updatetheclient(clients_book.add_people(), peo);
boardcast(epollfd, fd);
}
int leftLength = fd_msg->totalLength - (5 + contentLength);
char* leftBytes = new char[fd_msg->totalLength];
for (int i = contentLength + 5; i < fd_msg->totalLength; i++) {
leftBytes[i - 5 - contentLength] = fd_msg->totalBytes[i];
}
fd_msg->totalBytes = new char(leftLength);
for (int i = 0; i < leftLength; i++) {
fd_msg->totalBytes[i] = leftBytes[i];
}
fd_msg->totalLength = leftLength;
}
}
}
void handle_write(int epollfd, int fd)
{
pack();
write(fd, message, len + 5);
modify_event(epollfd, fd, EPOLLIN);
}
void handle_epoll_events(int epollfd, struct epoll_event *events, int num, int serv_sock){
for (int i = 0; i < num; i++) {
int fd = events[i].data.fd;
if ((fd == serv_sock) && (events[i].events & EPOLLIN)) {
handle_accept(epollfd, serv_sock);
} else if (events[i].events & EPOLLIN) {
handle_read(epollfd, fd);
} else if (events[i].events & EPOLLOUT) {
handle_write(epollfd, fd);
}
}
}
int main(int argc, char* argv[]) {
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(1234);
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(serv_sock, 20);
int epollfd = epoll_create(FD_SIZE);
add_epoll_event(epollfd, serv_sock, EPOLLIN);
struct epoll_event events[EPOLL_EVENTS];
while(1) {
int ret = epoll_wait(epollfd,events,EPOLL_EVENTS,-1);
handle_epoll_events(epollfd,events,ret,serv_sock);
}
close(epollfd);
close(serv_sock);
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
d b c l i e n t . c p p dbclient.cpp dbclient.cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <bits/stdc++.h>
#include "db.pb.h"
using namespace std;
using namespace user;
const int HS = 4;
int sock, f;
Person peo;
string name, passwd, x, y;
char bytes[1505];
// int - > char4
auto intToChar4(int i)
{
auto result = new char[4];
result[0] = (i >> 24 & 0xFF);
result[1] = (i >> 16 & 0xFF);
result[2] = (i >> 8 & 0xFF);
result[3] = (i & 0xFF);
return result;
}
// int - > char
auto intToChar(int i)
{
char result = (i & 0xFF);
return result;
}
auto char4ToInt(char* bytes)
{
int num = bytes[3] & 0xFF;
num |= ((bytes[2] << 8) & 0xFF00);
num |= ((bytes[1] << 16) & 0xFF0000);
num |= ((bytes[0] << 24) & 0xFF000000);
return num;
}
void pack(int f, Person peo)
{
int len = peo.ByteSizeLong();
char* messagebody = new char[len];
peo.SerializeToArray(messagebody, len);
char* lengthBytes = new char[4];
lengthBytes = intToChar4(len + 1);
char messageid;
messageid = intToChar(f);
char* message = new char(len + 5);
for (int i = 0; i < 4; i++) {
message[i] = lengthBytes[i];
}
message[4] = messageid;
for (int i = 5; i < 5 + len; i++) {
message[i] = messagebody[i - 5];
}
write(sock, message, len + 5);
}
void input()
{
cout << "press 1 to register and place your origin position" << endl;
cout << "press 2 to login" << endl;
cin >> f;
if (f == 1) {
cout << "please input your username" << endl;
cin >> name;
cout << "please input your passwd" << endl;
cin >> passwd;
cout << "please input your origin positon x, y" << endl;
cin >> x >> y;
peo.set_name(name);
peo.set_passwd(passwd);
peo.set_x(x);
peo.set_y(y);
} else if (f == 2) {
cout << "please input your username" << endl;
cin >> name;
cout << "please input your passwd" << endl;
cin >> passwd;
} else if (f == 3) {
cout << "please input your next positon x, y" << endl;
cin >> x >> y;
}
pack(f, peo);
if (f == 2) {
char flag[1];
read(sock, flag, sizeof(flag));
cout << flag[0] << endl;
if (flag[0] == '1') {
cout << "you is logging." << endl;
int totalLength = 0, len = 0;
char* totalBytes = new char(0);
while ((len = read(sock, bytes, 1505)) != -1) {
int tmpLength = totalLength;
totalLength += len;
char* tmpBytes = new char[tmpLength];
for (int i = 0; i < tmpLength; i++) {
tmpBytes[i] = totalBytes[i];
}
totalBytes = new char[totalLength];
for (int i = 0; i < tmpLength; i++) {
totalBytes[i] = tmpBytes[i];
}
for (int i = tmpLength; i < totalLength; i++) {
totalBytes[i] = bytes[i - tmpLength];
}
while (totalLength >= 5) {
char *lengthBytes = new char[4];
for (int i = 0; i < 4; i++) {
lengthBytes[i] = totalBytes[i];
}
int contentLength = char4ToInt(lengthBytes) - 1;
char messageid = totalBytes[4];
int f = messageid & 0xFF;
if (totalLength < contentLength + 5) {
break;
}
char* contentBytes = new char[contentLength];
for (int i = 0; i < contentLength; i++) {
contentBytes[i] = totalBytes[i + 5];
}
Person peo;
peo.ParseFromArray(contentBytes, contentLength);
cout << "now " << peo.name() << "'position is (" << peo.x() << ", " << peo.y() << ")" << endl;
cout << "press 3 to change your postion" << endl;
cout << "press other keys not to change your positon" << endl;
cin >> f;
if (f == 3) {
cout << "please input your next position" << endl;
cin >> x >> y;
peo.set_x(x);
peo.set_y(y);
pack(f, peo);
}
int leftLength = totalLength - (5 + contentLength);
char* leftBytes = new char[totalLength];
for (int i = contentLength + 5; i < totalLength; i++) {
leftBytes[i - 5 - contentLength] = totalBytes[i];
}
totalBytes = new char(leftLength);
for (int i = 0; i < leftLength; i++) {
totalBytes[i] = leftBytes[i];
}
totalLength = leftLength;
}
}
} else {
cout << "your username or passwd is incorrect!!!" << endl;
}
}
}
int main(){
sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(1234);
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
while (true)
{
input();
}
close(sock);
return 0;
}
g++ dbserver.cpp db.pb.cc -o dbserver `pkg-config --cflags --libs protobuf` -std=c++17
g++ dbclient.cpp db.pb.cc -o dbclient `pkg-config --cflags --libs protobuf` -std=c++17
之后就无敌了。