C++网络C/S模型

这篇是关于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;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值