刚开始学习Windows下的网络编程,简单实现了一个能收发请求的服务端和客户端,还有一些地方没弄明白,先把代码放这,有空再回来整理。
tool.h和tool.cpp
主要定义了请求的包头和数据结构以及报文的序列化及反序列化。
参考内容:https://blog.csdn.net/chenbiyun940419/article/details/96455550
#include <iostream>
#include <vector>
#include <string>
#include <map>
enum OPT {
LOGINMSGE,
FRIEND_REQ,
FRIEND_RES,
CHAT_REQ,
CHAT_RES
};
typedef struct dataheader {
int opt;
} DATAHEADER;
typedef struct loginmsg : public dataheader {
loginmsg() { opt = LOGINMSGE; }
std::vector<std::string> vs;
} LOGINMSG;
typedef struct req_friend : public dataheader {
req_friend() { opt = FRIEND_REQ; }
} REQ_FRIEND;
typedef struct res_friend : public dataheader {
res_friend() { opt = FRIEND_RES; }
std::map<int, std::string> mis;
} RES_FRIEND;
typedef struct req_chat : public dataheader {
req_chat() { opt = CHAT_REQ; }
std::string str;
} REQ_CHAT;
typedef struct res_chat :public dataheader {
res_chat() { opt = CHAT_RES; }
std::string str;
} RES_CHAT;
void printmessage(char* recvbuf, int& step);
void serialize(char* Det, const int* Src, int& step);
void deserialize(int* Det, const char* Src, int& step);
void serialize(char* sendBuf, const std::string& str, int& step);
void deserialize(std::string& str, const char* recvBuf, int& step);
void serialize(char* sendBuf, const std::vector<int>& vec, int& step);
void deserialize(std::vector<int>& vec, const char* recvBuf, int& step);
void serialize(char* sendBuf, const std::vector<std::string>& vec, int& step);
void deserialize(std::vector<std::string>& vec, const char* recvBuf, int& step);
void serialize(char* sendBuf, std::map<int, std::string>& m, int& step);
void deserialize(std::map<int, std::string>& m, const char* recvBuf, int& step);
void serialize(char* sendbuf, DATAHEADER& dataheader, int& step);
void deserialize(DATAHEADER& dataheader, char* recvbuf, int& step);
void serialize(char* sendbuf, LOGINMSG& loginmsg, int& step);
void deserialize(LOGINMSG& loginmsg, char* recvbuf, int& step);
void serialize(char* sendbuf, REQ_FRIEND& req_friend, int& step);
void deserialize(REQ_FRIEND& req_friend, char* recvbuf, int& step);
void serialize(char* sendbuf, RES_FRIEND& res_friend, int& step);
void deserialize(RES_FRIEND& res_friend, char* recvbuf, int& step);
void serialize(char* sendbuf, REQ_CHAT& req_chat, int& step);
void deserialize(REQ_CHAT& req_chat, char* recvbuf, int& step);
void serialize(char* sendbuf, RES_CHAT& res_chat, int& step);
void deserialize(RES_CHAT& res_chat, char* recvbuf, int& step);
#include <string.h>
#include "tool.h"
using namespace std;
void printmessage(char* recvbuf, int& step)
{
string str;
deserialize(str, recvbuf, step);
cout << str << endl;
}
//int
void serialize(char* Det, const int* Src, int& step)
{
memcpy(Det + step, Src, sizeof(int));
step += sizeof(int);
}
void deserialize(int* Det, const char* Src, int& step)
{
memcpy(Det, Src + step, sizeof(int));
step += sizeof(int);
}
//string
void serialize(char* sendBuf, const string& str, int& step)
{
int size;
size = str.length();
serialize(sendBuf, &size, step);
memcpy(sendBuf + step, &str[0], size);
step += size;
}
void deserialize(string& str, const char* recvBuf, int& step)
{
int size;
deserialize(&size, recvBuf, step);
str = string(recvBuf + step, size);
step += size;
}
//vector<int>
void serialize(char* sendBuf, const vector<int>& vec, int& step)
{
int size = vec.size();
serialize(sendBuf, &size, step);
memcpy(sendBuf + step, &vec[0], size * sizeof(int));
step += size * sizeof(int);
}
void deserialize(vector<int>& vec, const char* recvBuf, int& step)
{
int size;
deserialize(&size, recvBuf, step);
vec.resize(size);
memcpy(&vec[0], recvBuf + step, size * sizeof(int));
step += size * sizeof(int);
}
//vector<string>
void serialize(char* sendBuf, const vector<string>& vec, int& step)
{
int size = vec.size();
serialize(sendBuf, &size, step);
for (auto it = vec.begin(); it != vec.end(); it++)
serialize(sendBuf, *it, step);
}
void deserialize(vector<string>& vec, const char* recvBuf, int& step)
{
int size;
deserialize(&size, recvBuf, step);
string str;
if (!vec.empty())
vec.resize(0);
for (int i = 0; i < size; i++)
{
deserialize(str, recvBuf, step);
vec.insert(vec.end(), str);
}
}
//map<int,string>
void serialize(char* sendBuf, map<int, string>& m, int& step)
{
int size = m.size();
serialize(sendBuf, &size, step);
for (auto it = m.begin(); it != m.end(); it++)
{
serialize(sendBuf, &(it->first), step);
serialize(sendBuf, it->second, step);
}
}
void deserialize(map<int, string>& m, const char* recvBuf, int& step)
{
int size;
deserialize(&size, recvBuf, step);
int int_first;
string str_second;
if (!m.empty())
m.clear();
for (int i = 0; i < size; i++)
{
deserialize(&int_first, recvBuf, step);
deserialize(str_second, recvBuf, step);
m.insert(pair<int, string>(int_first, str_second));
}
}
void serialize(char* sendbuf, DATAHEADER& dataheader, int& step)
{
serialize(sendbuf, &dataheader.opt, step);
}
void deserialize(DATAHEADER& dataheader, char* recvbuf, int& step)
{
deserialize(&dataheader.opt, recvbuf, step);
}
void serialize(char* sendbuf, LOGINMSG& loginmsg, int& step)
{
serialize(sendbuf, &loginmsg.opt, step);
serialize(sendbuf, loginmsg.vs, step);
}
void deserialize(LOGINMSG& loginmsg, char* recvbuf, int& step)
{
deserialize(loginmsg.vs, recvbuf, step);
}
void serialize(char* sendbuf, REQ_FRIEND& req_friend, int& step)
{
serialize(sendbuf, &req_friend.opt, step);
}
void deserialize(REQ_FRIEND& req_friend, char* recvbuf, int& step)
{
deserialize(&req_friend.opt, recvbuf, step);
}
void serialize(char* sendbuf, RES_FRIEND& res_friend, int& step)
{
serialize(sendbuf, &res_friend.opt, step);
serialize(sendbuf, res_friend.mis, step);
}
void deserialize(RES_FRIEND& res_friend, char* recvbuf, int& step)
{
deserialize(res_friend.mis, recvbuf, step);
}
void serialize(char* sendbuf, REQ_CHAT& req_chat, int& step)
{
serialize(sendbuf, &req_chat.opt, step);
serialize(sendbuf, req_chat.str, step);
}
void deserialize(REQ_CHAT& req_chat, char* recvbuf, int& step)
{
deserialize(req_chat.str, recvbuf, step);
}
void serialize(char* sendbuf, RES_CHAT& res_chat, int& step)
{
serialize(sendbuf, &res_chat.opt, step);
serialize(sendbuf, res_chat.str, step);
}
void deserialize(RES_CHAT& res_chat, char* recvbuf, int& step)
{
deserialize(res_chat.str, recvbuf, step);
}
server.cpp?服务端实现
#define _CRT_SECURE_NO_WARNINGS
#include <winsock2.h>
#include "tool.h"
#pragma comment (lib, "ws2_32.lib")
using namespace std;
#define SRVIP "127.0.0.1"
#define SRVPORT 6666
map<SOCKET, HANDLE> sh;
void logincheck(SOCKET& clientsocket, char* recvbuf, int& step)
{
char sendbuf[1024] = {};
memset(sendbuf, 0, sizeof(sendbuf));
LOGINMSG loginmsg = {};
deserialize(loginmsg, recvbuf, step);
if (!strcmp(loginmsg.vs[0].c_str(), "luo") && !strcmp(loginmsg.vs[1].c_str(), "123456"))
{
loginmsg.vs[0] = "success";
cout << "login success" << endl;
}
else
{
loginmsg.vs[0] = "fail";
cout << "login fail" << endl;
}
step = 0;
serialize(sendbuf, loginmsg, step);
int ret = send(clientsocket, sendbuf, sizeof(sendbuf), 0);
if (ret == -1 || ret == 0)
{
cout << "send error:" << strerror(errno) << " errno:" << errno << endl;
return;
}
}
void friendlist(SOCKET& clientsocket)
{
RES_FRIEND res_friend = {};
char sendbuf[1024] = {};
int step = 0;
res_friend.mis.insert(pair<int, string>(1, "qwert"));
res_friend.mis.insert(pair<int, string>(2, "asdfgh"));
res_friend.mis.insert(pair<int, string>(3, "zxcvbnm"));
serialize(sendbuf, res_friend, step);
int ret = send(clientsocket, sendbuf, sizeof(sendbuf), 0);
if (ret == -1 || ret == 0)
{
cout << "send error:" << strerror(errno) << " errno:" << errno << endl;
return;
}
}
DWORD WINAPI sendmessage(const LPVOID param)
{
SOCKET clientsocket = *(static_cast<SOCKET*>(param));
char sendbuf[1024] = {};
RES_CHAT res_chat = {};
int step;
while (1)
{
memset(&sendbuf, 0, sizeof(sendbuf));
cout << "please input your message" << endl;
cin >> res_chat.str;
step = 0;
serialize(sendbuf, res_chat, step);
int ret = send(clientsocket, sendbuf, sizeof(sendbuf), 0);
if (ret == -1 || ret == 0)
{
cout << "send error:" << strerror(errno) << " errno:" << errno << endl;
break;
}
}
return 0;
}
void chatmessage(SOCKET& clientsocket, char* recvbuf, int& step)
{
printmessage(recvbuf, step);
if (sh.find(clientsocket) == sh.end())
{
HANDLE sendThread;
sendThread = CreateThread(NULL, 0, &sendmessage, &clientsocket, 0, NULL);
sh.insert(pair<SOCKET, HANDLE>(clientsocket, sendThread));
}
}
DWORD WINAPI run(const LPVOID param)
{
SOCKET clientsocket = *(static_cast<SOCKET*>(param));
char recvbuf[1024] = {};
int step;
DATAHEADER dataheader = {};
while (1)
{
memset(recvbuf, 0, sizeof(recvbuf));
int ret = recv(clientsocket, recvbuf, sizeof(recvbuf), 0);
if (ret == 0 || ret == -1)
{
cout << "the client has closed" << endl;
break;
}
cout << "get message from client" << endl;
step = 0;
deserialize(dataheader, recvbuf, step);
switch (dataheader.opt)
{
case LOGINMSGE:
{
logincheck(clientsocket, recvbuf, step);
break;
}
case FRIEND_REQ:
{
friendlist(clientsocket);
break;
}
case CHAT_REQ:
{
chatmessage(clientsocket, recvbuf, step);
break;
}
default:
{
cout << "req error" << endl;
break;
}
}
}
closesocket(clientsocket);
return 0;
}
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET serversocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serversocket < 0)
{
cout << "create socket error:" << strerror(errno) << " errno:" << errno << endl;
exit(0);
}
cout << "create socket success" << endl;
sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons((u_short)SRVPORT);
serverAddr.sin_addr.s_addr = inet_addr(SRVIP);
if (bind(serversocket, reinterpret_cast<sockaddr*>(&serverAddr), sizeof(sockaddr)) == -1)
{
cout << "bind error:" << strerror(errno) << " errno:" << errno << endl;
exit(0);
}
cout << "bind success" << endl;
if (listen(serversocket, 10) == -1)
{
cout << "listen error:" << strerror(errno) << " errno:" << errno << endl;
exit(0);
}
cout << "listen success" << endl;
HANDLE recvThread;
while (1)
{
SOCKET conn_fd = accept(serversocket, NULL, NULL);
if (conn_fd != -1)
cout << "accppet a client" << endl;
recvThread = CreateThread(NULL, 0, &run, &conn_fd, 0, NULL);
CloseHandle(recvThread);
}
closesocket(serversocket);
WSACleanup();
return 0;
}
client.cpp?客户端实现
#define _CRT_SECURE_NO_WARNINGS
#include <winsock2.h>
#include <windows.h>
#include "tool.h"
#pragma comment (lib, "ws2_32.lib")
using namespace std;
#define CLTIP "127.0.0.1"
#define SRVPORT 6666
bool logincheck(SOCKET& clientsocket)
{
bool loginstate = false;
int step;
char sendbuf[1024] = {};
char recvbuf[1024] = {};
LOGINMSG loginmsg = {};
string name, password;
while (!loginstate)
{
memset(sendbuf, 0, sizeof(sendbuf));
memset(recvbuf, 0, sizeof(recvbuf));
if (!loginmsg.vs.empty())
loginmsg.vs.resize(0);
cout << "please input your name" << endl;
cin >> name;
loginmsg.vs.push_back(name);
cout << "please input your password" << endl;
cin >> password;
loginmsg.vs.push_back(password);
step = 0;
serialize(sendbuf, loginmsg, step);
int ret = send(clientsocket, sendbuf, sizeof(sendbuf), 0);
if (ret == -1 || ret == 0)
{
cout << "send error:" << strerror(errno) << " errno:" << errno << endl;
break;
}
ret = recv(clientsocket, recvbuf, sizeof(recvbuf), 0);
if (ret == -1 || ret == 0)
{
cout << "the server close" << endl;
break;
}
cout << "get message from server" << endl;
DATAHEADER dataheader = {};
step = 0;
deserialize(dataheader, recvbuf, step);
deserialize(loginmsg, recvbuf, step);
if (!strcmp(loginmsg.vs[0].c_str(), "success"))
{
loginstate = true;
cout << "login success" << endl;
}
else
cout << "login fail" << endl;
}
return loginstate;
}
void printfriend(char* recvbuf, int& step)
{
map<int, string> fl;
deserialize(fl, recvbuf, step);
for (auto it = fl.begin(); it != fl.end(); it++)
cout << "<" << it->first << "," << it->second << ">" << " ";
cout << endl;
}
void reqfriend(char* sendbuf)
{
REQ_FRIEND req_friend = {};
int step = 0;
serialize(sendbuf, req_friend, step);
}
void reqchat(char* sendbuf)
{
REQ_CHAT req_chat = {};
int step = 0;
cout << "please input your message" << endl;
cin >> req_chat.str;
serialize(sendbuf, req_chat, step);
}
DWORD WINAPI sendmessage(const LPVOID param)
{
SOCKET clientsocket = *(static_cast<SOCKET*>(param));
char sendbuf[1024] = {};
int opt;
while (1)
{
memset(&sendbuf, 0, sizeof(sendbuf));
FLAG: Sleep(500);
cout << "please input your operator" << endl;
cout << "1.friend map<int,string>" << endl;
cout << "2.chat" << endl;
cin >> opt;
switch (opt)
{
case 1:
{
reqfriend(sendbuf);
break;
}
case 2:
{
reqchat(sendbuf);
break;
}
default:
{
cout << "error operator" << endl;
goto FLAG;
}
}
int ret = send(clientsocket, sendbuf, sizeof(sendbuf), 0);
if (ret == -1 || ret == 0)
{
cout << "send error:" << strerror(errno) << " errno:" << errno << endl;
break;
}
}
closesocket(clientsocket);
return 0;
}
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET clientsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientsocket < 0)
{
cout << "create socket error:" << strerror(errno) << " errno:" << errno << endl;
exit(0);
}
cout << "create socket success" << endl;
sockaddr_in clientAddr;
memset(&clientAddr, 0, sizeof(clientAddr));
clientAddr.sin_family = AF_INET;
clientAddr.sin_port = htons((u_short)SRVPORT);
clientAddr.sin_addr.s_addr = inet_addr(CLTIP);
if (connect(clientsocket, reinterpret_cast<sockaddr*>(&clientAddr), sizeof(sockaddr)) < 0)
{
cout << "connect error:" << strerror(errno) << " errno:" << errno << endl;
exit(0);
}
cout << "connect success" << endl;
if (logincheck(clientsocket))
{
HANDLE sendThread;
sendThread = CreateThread(NULL, 0, &sendmessage, &clientsocket, 0, NULL);
CloseHandle(sendThread);
char recvbuf[1024] = {};
int step;
while (1)
{
memset(recvbuf, 0, sizeof(recvbuf));
int ret = recv(clientsocket, recvbuf, sizeof(recvbuf), 0);
if (ret == -1 || ret == 0)
{
cout << "the server close" << endl;
break;
}
cout << "get message from server" << endl;
DATAHEADER dataheader = {};
step = 0;
deserialize(dataheader, recvbuf, step);
switch (dataheader.opt)
{
case FRIEND_RES:
{
printfriend(recvbuf, step);
break;
}
case CHAT_RES:
{
printmessage(recvbuf, step);
break;
}
default:
{
cout << "error res" << endl;
break;
}
}
}
}
closesocket(clientsocket);
WSACleanup();
return 0;
}
|