创建server端
该server端可以连接多个客户端,但不可以和单个客户端进行多次交互
#define WIN32_LEAN_AND_MEAN //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //method_1
int main02()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat); //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
//1.创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //地址系列规范,套接字规范,使用的协议
//2.绑定地址
sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
server_addr.sin_addr.S_un.S_addr = INADDR_ANY; //代表本机所有地址
int ret = bind(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in)); //若成功返回0
if (SOCKET_ERROR == ret)
{
std::cout << "绑定错误" << std::endl;
}
//3.监听端口
ret = listen(sock, 5); //第二个参数为挂起的连接队列的最大长度,若成功返回0
if (SOCKET_ERROR == ret)
{
std::cout << "监听错误" << std::endl;
}
//4.接收客户端连接
sockaddr_in client_addr = {};
int len = sizeof(sockaddr_in);
char buf[] = "hello, i'm server";
while (true)
{
SOCKET client_sock = accept(sock, (sockaddr*)&client_addr, &len); //accept函数返回一个新的套接字来和客户端通信,sockaddr和sockaddr_in所代表的意义一样,字节大小也一样,只不过sockaddr_in是后面创建的,之前的接口没有更改
if (INVALID_SOCKET == client_sock)
{
std::cout << "连接客户端错误" << std::endl;
}
std::cout << "客户端:" << inet_ntoa(client_addr.sin_addr) << "连接成功" << std::endl;
//5.发送数据
int buf_len = send(client_sock, buf, sizeof(buf), 0); //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
if (SOCKET_ERROR == buf_len)
{
std::cout << "发送错误" << std::endl;
}
}
//6.关闭套接字
closesocket(sock);
WSACleanup();
return 0;
}
该server端可以和单个客户端进行多次交互,但不可以连接多个客户端并和多个客户端进行交互
#define WIN32_LEAN_AND_MEAN //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //method_1
struct DataPackage
{
int age;
char name[32];
};
int main()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat); //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
//1.创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //地址系列规范,套接字规范,使用的协议
//2.绑定地址
sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
server_addr.sin_addr.S_un.S_addr = INADDR_ANY; //代表本机所有地址
int ret = bind(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in)); //若成功返回0
if (SOCKET_ERROR == ret)
{
std::cout << "绑定错误" << std::endl;
}
//3.监听端口
ret = listen(sock, 5); //第二个参数为挂起的连接队列的最大长度,若成功返回0
if (SOCKET_ERROR == ret)
{
std::cout << "监听错误" << std::endl;
}
//4.接收客户端连接,
sockaddr_in client_addr = {};
int len = sizeof(sockaddr_in);
char buf[] = "hello, i'm server";
char recv_buf[128] = {};
char send_buf[128] = {};
std::cout << typeid(recv_buf).name() << std::endl;
//accept函数放在循坏外面,证明只能处理一个客户端的请求
SOCKET client_sock = accept(sock, (sockaddr*)&client_addr, &len); //accept函数返回一个新的套接字来和客户端通信,sockaddr和sockaddr_in所代表的意义一样,字节大小也一样,只不过sockaddr_in是后面创建的,之前的接口没有更改
if (INVALID_SOCKET == client_sock)
{
std::cout << "连接客户端错误" << std::endl;
}
std::cout << "客户端:" << inet_ntoa(client_addr.sin_addr) << "连接成功" << std::endl;
//5.发送数据
int buf_len = send(client_sock, buf, sizeof(buf), 0); //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
if (SOCKET_ERROR == buf_len)
{
std::cout << "发送错误" << std::endl;
}
while (true)
{
//6.接收数据
buf_len = recv(client_sock, recv_buf, 128, 0);
//7.处理数据
if (SOCKET_ERROR == buf_len)
{
std::cout << "接收错误" << std::endl;
break;
}
else
{
std::cout << "接收请求:" << recv_buf << std::endl;
if (strncmp(recv_buf, "exit", 4) == 0)
{
std::cout << "客户端连接退出" << std::endl;
break;
}
else if (strncmp(recv_buf, "get_info_struct", sizeof("get_info_struct")) == 0)
{
DataPackage data = {18, "aaron"};
buf_len = send(client_sock, (char *)&data, sizeof(send_buf), 0); //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
if (SOCKET_ERROR == buf_len)
{
std::cout << "发送错误" << std::endl;
}
}
else if (strncmp(recv_buf, "get_name", sizeof("get_name")) == 0)
{
strcpy(send_buf, "aaron");
buf_len = send(client_sock, send_buf, sizeof(send_buf), 0);
if (SOCKET_ERROR == buf_len)
{
std::cout << "发送错误" << std::endl;
}
}
else if (strncmp(recv_buf, "get_age", sizeof("get_age")) == 0)
{
strcpy(send_buf, "18");
buf_len = send(client_sock, send_buf, sizeof(send_buf), 0);
if (SOCKET_ERROR == buf_len)
{
std::cout << "发送错误" << std::endl;
}
}
else
{
strcpy(send_buf, "不合理的请求,请重新发送");
buf_len = send(client_sock, send_buf, sizeof(send_buf), 0);
if (SOCKET_ERROR == buf_len)
{
std::cout << "发送错误" << std::endl;
}
}
}
}
std::cout << "服务器退出" << std::endl;
//8.关闭套接字
closesocket(sock);
WSACleanup();
return 0;
}
服务器模拟网络报文分别发送报文头和报文体和客户端进行交互
#define WIN32_LEAN_AND_MEAN //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //method_1
enum CMD
{
CMD_LOGIN,
CMD_LOGOUT,
CMD_EXIT
};
struct DataHeader
{
short data_length;
short cmd;
};
struct Login
{
char username[32];
char password[32];
};
struct LoginResult
{
int result;
};
struct Logout
{
char username[32];
};
struct LogoutResult
{
int result;
};
bool judge_return_value(char* function_name, int ret)
{
if (SOCKET_ERROR == ret)
{
std::cout << function_name << "错误"<< std::endl;
return TRUE;
}
return FALSE;
}
int main()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat); //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
//1.创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //地址系列规范,套接字规范,使用的协议
//2.绑定地址
sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
server_addr.sin_addr.S_un.S_addr = INADDR_ANY; //代表本机所有地址
int ret = bind(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in)); //若成功返回0
judge_return_value("bind", ret);
//3.监听端口
ret = listen(sock, 5); //第二个参数为挂起的连接队列的最大长度,若成功返回0
judge_return_value("listen", ret);
//4.接收客户端连接,
sockaddr_in client_addr = {};
int len = sizeof(sockaddr_in);
char buf[] = "hello, i'm server";
char recv_buf[128] = {};
char send_buf[128] = {};
//std::cout << typeid(recv_buf).name() << std::endl;
//accept函数放在循坏外面,证明只能处理一个客户端的请求
SOCKET client_sock = accept(sock, (sockaddr*)&client_addr, &len); //accept函数返回一个新的套接字来和客户端通信,sockaddr和sockaddr_in所代表的意义一样,字节大小也一样,只不过sockaddr_in是后面创建的,之前的接口没有更改
if (INVALID_SOCKET == client_sock)
{
std::cout << "连接客户端错误" << std::endl;
}
std::cout << "客户端:" << inet_ntoa(client_addr.sin_addr) << "连接成功" << std::endl;
//5.发送数据
int buf_len = send(client_sock, buf, sizeof(buf), 0); //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
judge_return_value("send", buf_len);
while (true)
{
//6.接收数据
DataHeader header = {};
buf_len = recv(client_sock, (char*)&header, sizeof(DataHeader), 0);
//7.处理数据
if (judge_return_value("recv", buf_len))
{
break;
}
else
{
std::cout << "接收请求:" << header.cmd << "报文长度:" << header.data_length <<std::endl;
if (header.cmd == CMD_EXIT)
{
std::cout << "客户端连接退出" << std::endl;
break;
}
else if (header.cmd == CMD_LOGIN)
{
Login data = {};
buf_len = recv(client_sock, (char *)&data, sizeof(Login), 0); //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
judge_return_value("recv", buf_len);
LoginResult res = {};
if (!strncmp(data.username, "aaron", sizeof("aaron") && !strncmp(data.password, "123456", sizeof("123456"))))
{
res.result = 1;
}
else
{
res.result = 0;
}
buf_len = send(client_sock, (char *)&res, sizeof(LoginResult), 0);
judge_return_value("send", buf_len);
}
else if (header.cmd == CMD_LOGOUT)
{
Logout data = {};
buf_len = recv(client_sock, (char *)&data, sizeof(Logout), 0);
judge_return_value("recv", buf_len);
LoginResult res = {2};
buf_len = send(client_sock, (char *)&res, sizeof(LoginResult), 0);
judge_return_value("send", buf_len);
}
}
}
std::cout << "服务器退出" << std::endl;
getchar();
//8.关闭套接字
closesocket(sock);
WSACleanup();
return 0;
}
服务器模拟网络报文同时发送报文头和报文体和客户端进行交互
#define WIN32_LEAN_AND_MEAN //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //method_1
enum CMD
{
CMD_LOGIN,
CMD_LOGIN_RESULT,
CMD_LOGOUT,
CMD_LOGOUT_RESULT,
CMD_EXIT
};
struct DataHeader
{
short data_length;
short cmd;
};
struct Login : public DataHeader
{
Login()
{
data_length = sizeof(Login);
cmd = CMD_LOGIN;
}
char username[32];
char password[32];
};
struct LoginResult : public DataHeader
{
LoginResult()
{
data_length = sizeof(LoginResult);
cmd = CMD_LOGIN_RESULT;
}
int result;
};
struct Logout : public DataHeader
{
Logout()
{
data_length = sizeof(Logout);
cmd = CMD_LOGOUT;
}
char username[32];
};
struct LogoutResult : public DataHeader
{
LogoutResult()
{
data_length = sizeof(LogoutResult);
cmd = CMD_LOGOUT_RESULT;
}
int result;
};
bool judge_return_value(char* function_name, int ret)
{
if (SOCKET_ERROR == ret)
{
std::cout << function_name << "错误" << std::endl;
return TRUE;
}
return FALSE;
}
int main()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat); //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
//1.创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //地址系列规范,套接字规范,使用的协议
//2.绑定地址
sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
server_addr.sin_addr.S_un.S_addr = INADDR_ANY; //代表本机所有地址
int ret = bind(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in)); //若成功返回0
judge_return_value("bind", ret);
//3.监听端口
ret = listen(sock, 5); //第二个参数为挂起的连接队列的最大长度,若成功返回0
judge_return_value("listen", ret);
//4.接收客户端连接,
sockaddr_in client_addr = {};
int len = sizeof(sockaddr_in);
char buf[] = "hello, i'm server";
char recv_buf[128] = {};
char send_buf[128] = {};
//std::cout << typeid(recv_buf).name() << std::endl;
//accept函数放在循坏外面,证明只能处理一个客户端的请求
SOCKET client_sock = accept(sock, (sockaddr*)&client_addr, &len); //accept函数返回一个新的套接字来和客户端通信,sockaddr和sockaddr_in所代表的意义一样,字节大小也一样,只不过sockaddr_in是后面创建的,之前的接口没有更改
if (INVALID_SOCKET == client_sock)
{
std::cout << "连接客户端错误" << std::endl;
}
std::cout << "客户端:" << inet_ntoa(client_addr.sin_addr) << "连接成功" << std::endl;
//5.发送数据
int buf_len = send(client_sock, buf, sizeof(buf), 0); //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
judge_return_value("send", buf_len);
while (true)
{
//6.接收数据
DataHeader header = {};
buf_len = recv(client_sock, (char*)&header, sizeof(DataHeader), 0);
//7.处理数据
if (judge_return_value("recv", buf_len))
{
break;
}
else
{
if (header.cmd == CMD_EXIT)
{
std::cout << "客户端连接退出" << std::endl;
break;
}
else if (header.cmd == CMD_LOGIN)
{
Login data = {};
buf_len = recv(client_sock, (char *)&data + sizeof(DataHeader), sizeof(Login) - sizeof(DataHeader), 0); //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
judge_return_value("recv", buf_len);
std::cout << "接收请求:LOGIN" << ",数据长度:" << data.data_length << ",用户名:" << data.username << std::endl;
LoginResult res = {};
if (!strncmp(data.username, "aaron", sizeof("aaron") && !strncmp(data.password, "123456", sizeof("123456"))))
{
res.result = 0; //网络通信一般返回0为正常
}
else
{
res.result = 1;
}
buf_len = send(client_sock, (char *)&res, sizeof(LoginResult), 0);
judge_return_value("send", buf_len);
}
else if (header.cmd == CMD_LOGOUT)
{
Logout data = {};
buf_len = recv(client_sock, (char *)&data + sizeof(DataHeader), sizeof(Logout) - sizeof(DataHeader), 0);
judge_return_value("recv", buf_len);
std::cout << "接收请求:LOGOUT" << ",数据长度:" << data.data_length << ",用户名:" << data.username << std::endl;
LogoutResult res = {};
res.result = 0;
buf_len = send(client_sock, (char *)&res, sizeof(LogoutResult), 0);
judge_return_value("send", buf_len);
}
}
}
std::cout << "服务器退出" << std::endl;
getchar();
//8.关闭套接字
closesocket(sock);
WSACleanup();
return 0;
}
创建客户端
只进行服务器的连接测试
#define WIN32_LEAN_AND_MEAN //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //method_1
struct DataPackage
{
int age;
char name[32];
};
int main()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat); //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
//创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //客户端的地址由系统自动分配,不需要绑定
//连接服务器
sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
int ret = connect(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in)); //如果未发生错误,则返回零
if (SOCKET_ERROR == ret)
{
std::cout << "连接建立出错" << std::endl;
}
//接受消息
char buf[128] = {};
int buf_len = recv(sock, buf, 128, 0);
if (SOCKET_ERROR == buf_len)
{
std::cout << "接收错误" << std::endl;
}
std::cout << buf << std::endl;
getchar();
//关闭套接字
closesocket(sock);
WSACleanup();
return 0;
}
可以和服务器进行结构化数据的交互
#define WIN32_LEAN_AND_MEAN //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //method_1
struct DataPackage
{
int age;
char name[32];
};
int main()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat); //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
//创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //客户端的地址由系统自动分配,不需要绑定
//连接服务器
sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
int ret = connect(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in)); //如果未发生错误,则返回零
if (SOCKET_ERROR == ret)
{
std::cout << "连接建立出错" << std::endl;
}
//接受消息
char buf[128] = {};
int buf_len = recv(sock, buf, 128, 0);
if (SOCKET_ERROR == buf_len)
{
std::cout << "接收错误" << std::endl;
}
std::cout << buf << std::endl;
char recv_buf[128] = {};
char send_buf[128] = {};
while (true)
{
//输入数据
std::cin >> send_buf;
if (strncmp(send_buf, "exit", 4) == 0)
{
buf_len = send(sock, send_buf, sizeof(send_buf), 0); //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
if (SOCKET_ERROR == buf_len)
{
std::cout << "发送错误" << std::endl;
}
break;
}
buf_len = send(sock, send_buf, sizeof(send_buf), 0);
if (SOCKET_ERROR == buf_len)
{
std::cout << "发送错误" << std::endl;
}
buf_len = recv(sock, recv_buf, 128, 0);
DataPackage* data = (DataPackage* )recv_buf;
if (SOCKET_ERROR == buf_len)
{
std::cout << "接收错误" << std::endl;
}
std::cout << data->age << data->name << std::endl;
}
std::cout << "连接退出" << std::endl;
getchar();
//关闭套接字
closesocket(sock);
WSACleanup();
return 0;
}
可以和服务器进行报文模式的结构化数据的交互
#define WIN32_LEAN_AND_MEAN //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //method_1
bool judge_return_value(char* function_name, int ret)
{
if (SOCKET_ERROR == ret)
{
std::cout << function_name << "错误" << std::endl;
return FALSE;
}
return TRUE;
}
enum CMD
{
CMD_LOGIN,
CMD_LOGOUT,
CMD_EXIT
};
struct DataHeader
{
short data_length;
short cmd;
};
struct Login
{
char username[32];
char password[32];
};
struct LoginResult
{
int result;
};
struct Logout
{
char username[32];
};
struct LogoutResult
{
int result;
};
int main()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat); //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
//创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //客户端的地址由系统自动分配,不需要绑定
//连接服务器
sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
int ret = connect(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in)); //如果未发生错误,则返回零
judge_return_value("connect", ret);
//接受消息
char buf[128] = {};
int buf_len = recv(sock, buf, 128, 0);
judge_return_value("recv", buf_len);
std::cout << buf << std::endl;
char recv_buf[128] = {};
char send_buf[128] = {};
while (true)
{
//输入数据
std::cin >> send_buf;
if (strncmp(send_buf, "exit", sizeof("exit")) == 0)
{
DataHeader header = { 0, CMD_EXIT };
buf_len = send(sock, (char*)&header, sizeof(DataHeader), 0);
judge_return_value("send", buf_len);
break;
}
else if (strncmp(send_buf, "login", sizeof("login")) == 0)
{
Login info = {"aaron", "123456"};
DataHeader header = { sizeof(Login), CMD_LOGIN };
buf_len = send(sock, (char*)&header, sizeof(DataHeader), 0);
judge_return_value("send", buf_len);
buf_len = send(sock, (char*)&info, sizeof(Login), 0);
judge_return_value("send", buf_len);
LoginResult res = {};
buf_len = recv(sock, (char*)&res, sizeof(LoginResult), 0);
judge_return_value("recv", buf_len);
std::cout << res.result << std::endl;
}
else if (strncmp(send_buf, "logout", sizeof("logout")) == 0)
{
Logout info = { "aaron"};
DataHeader header = { sizeof(Logout), CMD_LOGOUT };
buf_len = send(sock, (char*)&header, sizeof(DataHeader), 0);
judge_return_value("send", buf_len);
buf_len = send(sock, (char*)&info, sizeof(Logout), 0);
judge_return_value("send", buf_len);
LogoutResult res = {};
buf_len = recv(sock, (char*)&res, sizeof(LoginResult), 0);
judge_return_value("recv", buf_len);
std::cout << res.result << std::endl;
}
}
std::cout << "连接退出" << std::endl;
getchar();
//关闭套接字
closesocket(sock);
WSACleanup();
return 0;
}
可以和服务器进行整体报文模式的结构化数据的交互
#define WIN32_LEAN_AND_MEAN //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //method_1
bool judge_return_value(char* function_name, int ret)
{
if (SOCKET_ERROR == ret)
{
std::cout << function_name << "错误" << std::endl;
return FALSE;
}
return TRUE;
}
enum CMD
{
CMD_LOGIN,
CMD_LOGIN_RESULT,
CMD_LOGOUT,
CMD_LOGOUT_RESULT,
CMD_EXIT
};
struct DataHeader
{
short data_length;
short cmd;
};
struct Login : public DataHeader
{
Login()
{
data_length = sizeof(Login);
cmd = CMD_LOGIN;
}
char username[32];
char password[32];
};
struct LoginResult : public DataHeader
{
LoginResult()
{
data_length = sizeof(LoginResult);
cmd = CMD_LOGIN_RESULT;
}
int result;
};
struct Logout : public DataHeader
{
Logout()
{
data_length = sizeof(Logout);
cmd = CMD_LOGOUT;
}
char username[32];
};
struct LogoutResult : public DataHeader
{
LogoutResult()
{
data_length = sizeof(LogoutResult);
cmd = CMD_LOGOUT_RESULT;
}
int result;
};
int main()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat); //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
//创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //客户端的地址由系统自动分配,不需要绑定
//连接服务器
sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
int ret = connect(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in)); //如果未发生错误,则返回零
judge_return_value("connect", ret);
//接受消息
char buf[128] = {};
int buf_len = recv(sock, buf, 128, 0);
judge_return_value("recv", buf_len);
std::cout << buf << std::endl;
char recv_buf[128] = {};
char send_buf[128] = {};
while (true)
{
//输入数据
std::cin >> send_buf;
if (strncmp(send_buf, "exit", sizeof("exit")) == 0)
{
DataHeader header = { 0, CMD_EXIT };
buf_len = send(sock, (char*)&header, sizeof(DataHeader), 0);
judge_return_value("send", buf_len);
break;
}
else if (strncmp(send_buf, "login", sizeof("login")) == 0)
{
Login info = {};
strcpy(info.username, "aaron");
strcpy(info.password, "123456");
buf_len = send(sock, (char*)&info, sizeof(Login), 0);
judge_return_value("send", buf_len);
LoginResult res = {};
buf_len = recv(sock, (char*)&res, sizeof(LoginResult), 0);
judge_return_value("recv", buf_len);
std::cout << "数据指令:" << res.cmd << ",数据长度:" << res.data_length << ",返回:"<<res.result << std::endl;
}
else if (strncmp(send_buf, "logout", sizeof("logout")) == 0)
{
Logout info = { };
strcpy(info.username, "aaron");
buf_len = send(sock, (char*)&info, sizeof(Logout), 0);
judge_return_value("send", buf_len);
LogoutResult res = {};
buf_len = recv(sock, (char*)&res, sizeof(LoginResult), 0);
judge_return_value("recv", buf_len);
std::cout << "数据指令:" << res.cmd << ",数据长度:" << res.data_length << ",返回:" << res.result << std::endl;
}
}
std::cout << "连接退出" << std::endl;
getchar();
//关闭套接字
closesocket(sock);
WSACleanup();
return 0;
}