这篇是关于C++网络C/S模型简单的代码实现,仅限与代码的实现
非封装的服务端代码
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")int main() {
WSADATA date{};
if (WSAStartup(MAKEWORD(2, 2), &date) == SOCKET_ERROR) {
std::cout << "WSAStartup func error" <<WSAGetLastError() << std::endl;
return -1;
}SOCKET servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (servSock == INVALID_SOCKET) {
std::cout << "socket func error" << WSAGetLastError() << std::endl;
WSACleanup();
return -1;
}
sockaddr_in sercaddr;
sercaddr.sin_family = AF_INET;
//两个函数解析 htons()将本地字节序转化为网络字节序
// 将端口号转化为网络字节序
// htonl() 将IP 转化为网络字节序 这个函数由安全隐患
// 所以我们有inet_pton函数
sercaddr.sin_port = htons(2345);
inet_pton(AF_INET, "127.0.0.1", &sercaddr.sin_addr.S_un.S_addr);if (bind(servSock, (sockaddr*)&sercaddr, sizeof(sockaddr)) == INVALID_SOCKET)
{
std::cout << "bind func error" << WSAGetLastError() << std::endl;
WSACleanup();
return -1;
}
if (listen(servSock, 128) == -1) {
std::cout << "listen func error" << WSAGetLastError() << std::endl;
WSACleanup();
return -1;
}
SOCKET clntSock = accept(servSock, nullptr, nullptr);
if (clntSock == INVALID_SOCKET) {
std::cout << "socket func error" << WSAGetLastError() << std::endl;
WSACleanup();
return -1;
}
const char* mes = "Hello 呀!";
char recevbuf[128]{};
if (send(clntSock, mes, strlen(mes), 0) < 0) {
std::cout << "send func error" << WSAGetLastError() << std::endl;
closesocket(servSock);
closesocket(clntSock);
WSACleanup();
}
// send函数中第一个参数指的是向哪个协议栈发送信息
// 第二个参数发送信息的地址
// 第三个参数指发送信息的地址长度
// 第四个参数指的是发送方式 一般写为0即可int rev = recv(servSock, recevbuf, 128,0); 当recv函数成功调用 会返回缓冲区大小
if (rev == 0) {
std::cout << "client drop the connnection gracefully" << std::endl;}
if (rev < 0) {
int errornum = WSAGetLastError();
if (errornum == 10054) {
std::cout << "客户端强制断开" << std::endl;
}
else {
std::cout << "recv func error" << WSAGetLastError() << std::endl;
closesocket(servSock);
closesocket(clntSock);
WSACleanup();
return -1;
}
}
// recv函数中第一个参数指的是哪个协议栈接受信息
// 第二个参数一个用户定义的缓冲区
// 第三个参数指的是缓冲区的最大长度
// 第四个参数指的是接受方式
// 当recv函数成功调用 会返回缓冲区大小
std::cout << recevbuf << std::endl;
closesocket(servSock);
closesocket(clntSock);
WSACleanup();//网络网卡也属于一个设备模块,所以我们也要进行清理
system("pause");
return 0;}
以上函数参考linux网络开发中有讲解。区别在与C++中recv函数和send函数 这两个发送和接收信息以封装完成
未封装的客户端代码
#include<WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")int main() {
WSADATA date{};
if (WSAStartup(MAKEWORD(2, 2), &date) == SOCKET_ERROR) {
std::cout << "WSAStartup func error" << WSAGetLastError() << std::endl;
return -1;
}SOCKET servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (servSock == INVALID_SOCKET) {
std::cout << "socket func error" << WSAGetLastError() << std::endl;
WSACleanup();
return -1;
}sockaddr_in sercadd;
sercadd.sin_family = AF_INET;
sercadd.sin_port = htons(2345);
inet_pton(AF_INET, "127.0.0.1", &sercadd.sin_addr.S_un.S_addr);
if (connect(servSock, (sockaddr*)&sercadd, sizeof(sercadd)) == SOCKET_ERROR) {
std::cout << "connection func error" << WSAGetLastError() << std::endl;
closesocket(servSock);
WSACleanup();
return -1;
}
char buf[128]{};
int recev = recv(servSock, buf, 128, 0);
if (recev == 0) {
std::cout << "服务器优雅的断开" << std::endl;
}
else if(recev<0){
int num = WSAGetLastError();
if (num == 10054) {
std::cout << "服务器强制断开" << std::endl;
}
else {
std::cout << "recv func error" << WSAGetLastError() << std::endl;
closesocket(servSock);
WSACleanup();
return -1;
}
}
if (send(servSock, buf, recev, 0) == SOCKET_ERROR) {
std::cout << "sebd func error" << WSAGetLastError() << std::endl;
closesocket(servSock);
WSACleanup();
return -1;
}
closesocket(servSock);
WSACleanup();
system("pause");
return 0;
}
以上是C++C/S模型没有分装,我们都知道C++需要进行封装的。以下是C++封装的代码
Server.h
#pragma once
#include <WinSock2.h>class Server
{
public:
Server();
~Server();
void close();
bool init(const char* ip, unsigned short port);
bool start(const char* ip, unsigned short port);
bool acceptClit();
bool sendMes(const char* mes);
bool rece();
const char* getmes();private:
SOCKET ServSock;
SOCKET ClntSock;
char buf[128]{};};
Server.cpp
#include "Server.h"
#include <iostream>
#include <WS2tcpip.h>
#include <assert.h>Server::Server():ServSock (INVALID_SOCKET),ClntSock(INVALID_SOCKET)
{
}Server::~Server()
{
close();
}void Server::close()
{
if (ServSock == INVALID_SOCKET) {
closesocket(ServSock);
if (ClntSock == INVALID_SOCKET);
closesocket(ClntSock);
WSACleanup();
ServSock = INVALID_SOCKET;
ClntSock = INVALID_SOCKET;}
}bool Server::init(const char* ip, unsigned short port)
{
WSADATA date{};
if (WSAStartup(MAKEWORD(2, 2), &date) == SOCKET_ERROR) {
std::cout << "WSAStartup func error" << WSAGetLastError() << std::endl;
return false;
}ServSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ServSock == INVALID_SOCKET) {
std::cout << "socket func error" << WSAGetLastError() << std::endl;
WSACleanup();
return false;
}
sockaddr_in sercaddr;
sercaddr.sin_family = AF_INET;
//两个函数解析 htons()将本地字节序转化为网络字节序
// 将端口号转化为网络字节序
// htonl() 将IP 转化为网络字节序 这个函数由安全隐患
// 所以我们有inet_pton函数
sercaddr.sin_port = htons(port);
inet_pton(AF_INET, ip, &sercaddr.sin_addr.S_un.S_addr);if (bind(ServSock, (sockaddr*)&sercaddr, sizeof(sockaddr)) == INVALID_SOCKET)
{
std::cout << "bind func error" << WSAGetLastError() << std::endl;
WSACleanup();
return false;
}
if (listen(ServSock, 128) == -1) {
std::cout << "listen func error" << WSAGetLastError() << std::endl;
WSACleanup();
return false;
}
}bool Server::start(const char* ip, unsigned short port)
{
if (!init(ip, port))
return false;
assert(ServSock != INVALID_SOCKET);
return true;}
bool Server::acceptClit()
{
ClntSock = accept(ServSock, nullptr, nullptr);
if (ClntSock == INVALID_SOCKET) {
std::cout << "ClntSock func error"
<< WSAGetLastError() << std::endl;
return false;}
}bool Server::sendMes(const char* mes)
{
if (send(ClntSock, mes, strlen(mes), 0) < 0) {
std::cout << "send func error" << WSAGetLastError() << std::endl;
WSACleanup();
return false;
}
}bool Server::rece()
{
int rev = recv(ServSock, buf, 128, 0);
if (rev == 0) {
std::cout << "client drop the connnection gracefully" << std::endl;}
if (rev < 0) {
int errornum = WSAGetLastError();
if (errornum == 10054) {
std::cout << "客户端强制断开" << std::endl;
}
else {
std::cout << "recv func error" << WSAGetLastError() << std::endl;
return false;
}
}
}const char* Server::getmes()
{
return buf;
}
main.cpp
#include "Server.h"
#include <iostream>
#pragma comment(lib,"ws2_32.lib")int main() {
Server ser;
if (!ser.start("127.0.0.1", 2345)) {
return -1;
}
if (!ser.acceptClit()) {
return -1;
}
const char* mes = "Hello";
if (!ser.sendMes(mes)) {
return -1;
}
if (ser.rece()) {
return -1;
}
std::cout << ser.getmes() << std::endl;
system("pasue");
return 0;
}
客户端
client.h
#pragma once
#include <WinSock2.h>
class Client
{
public:
Client();
~Client();
bool init(const char* ip, unsigned short port);
void close();
bool start(const char* ip, unsigned short port);
bool sendmes();
bool recvmes();
private:
SOCKET clntSock;
char buf[128]{};
int recvs = 0;
};
client.cpp
#include "Client.h"
#include <ws2tcpip.h>
#include <iostream>
Client::Client():clntSock(INVALID_SOCKET)
{
}Client::~Client()
{
close();
}bool Client::init(const char* ip, unsigned short port)
{
WSADATA data{};
if (WSAStartup(MAKEWORD(2, 2), &data) == SOCKET_ERROR)
{
std::cout << "WSAStartup func error, error num is : " << WSAGetLastError() << std::endl;
return -1;
}
clntSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clntSock == INVALID_SOCKET)
{
std::cout << "socket func error, error num is : " << WSAGetLastError() << std::endl;
WSACleanup();
return false;
}sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
inet_pton(AF_INET, ip, &servAddr.sin_addr.S_un.S_addr);
if (connect(clntSock, (sockaddr*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
{
std::cout << "connect func error, error num is : " << WSAGetLastError() << std::endl;
closesocket(clntSock);
WSACleanup();
return false;
}
return false;
}void Client::close()
{
if (clntSock == INVALID_SOCKET) {
close();
WSACleanup();
clntSock = INVALID_SOCKET;
}}
bool Client::start(const char* ip, unsigned short port)
{
if(!init(ip,port))
return false;
return true;
}bool Client::sendmes()
{
if (send(clntSock, buf, recvs, 0) == SOCKET_ERROR)
{
std::cout << "send func error, error num is : " << WSAGetLastError() << std::endl;
return false;}
}bool Client::recvmes()
{
recvs = recv(clntSock, buf, 128, 0);
if (recvs == 0) {
std::cout << "服务器优雅的断开" << std::endl;
}
else if (recvs < 0) {
int reeoenum = WSAGetLastError();
if (reeoenum == 10054) {
std::cout << "服务器强制断开" << std::endl;
}
else {
std::cout << "recv func error " << WSAGetLastError() << std::endl;
return false;
}
}
}
main.cpp
#include "Client.h"
#include <iostream>
#pragma comment(lib,"ws2_32.lib")int main() {
Client cl;
if (!cl.start("127.0.0.1", 2345)) {
return -1;
}
if (!cl.recvmes()) {
return -1;
}
if (!cl.sendmes()) {
return -1;
}}