Windows Practice_Socket 错误封装

UDP简单通讯例子

需要注意的是:
inet_addr函数如果使用的是VS2014以上的库编译时,会报错,所以我们需要选择兼容XP的编译方式,具体设置在项目属性中设置。如图所示:
这里写图片描述

服务端

// SocketUDPServer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#include <clocale>

#pragma comment(lib, "ws2_32.lib")


void PrintErrorMessage(DWORD dwErrorCode)
{
    setlocale(LC_ALL, "chs");
    wchar_t strErrorMessage[MAXBYTE] = { 0 };
    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, dwErrorCode, 0, strErrorMessage, MAXBYTE, nullptr);
    wprintf(L"ErrorCode:%d    ErrorMessage:%s", dwErrorCode, strErrorMessage);
}


int main()
{
    WSAData wsaData;
    int iErrorNumber = WSAStartup(MAKEWORD(2, 2), &wsaData);

    if (iErrorNumber != 0)
    {
        printf("WSAStartup failed with error: %d\n", iErrorNumber);
        return 1;
    }

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
    {
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
        return 1;
    }
    else
    {
        printf("The Winsock 2.2 dll was found okay\n");
    }

    SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (INVALID_SOCKET == s)
    {
        PrintErrorMessage(GetLastError());
        WSACleanup();
        return 1;
    }

    sockaddr_in sockaddrServer, socketaddrClient;
    sockaddrServer.sin_family = AF_INET;
    sockaddrServer.sin_port = htons(10086);
    sockaddrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    bind(s, reinterpret_cast<sockaddr *>(&sockaddrServer), sizeof(sockaddrServer));

    char buf[MAXBYTE] = { 0 };

    int iLen = sizeof(sockaddr_in);
    recvfrom(s, buf, MAXBYTE, 0, reinterpret_cast<sockaddr *>(&socketaddrClient), &iLen);

    printf("received from Client:%s\r\n", buf);
    scanf_s("%s", buf, MAXBYTE);
    sendto(s, buf, MAXBYTE, 0, reinterpret_cast<sockaddr *>(&socketaddrClient), MAXBYTE);

    closesocket(s);
    WSACleanup();

    system("pause");
    return 0;
}

客户端

// SocketUDPClient.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#include <clocale>

#pragma comment(lib, "ws2_32.lib")


void PrintErrorMessage(DWORD dwErrorCode)
{
    setlocale(LC_ALL, "chs");
    wchar_t strErrorMessage[MAXBYTE] = { 0 };
    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, dwErrorCode, 0, strErrorMessage, MAXBYTE, nullptr);
    wprintf(L"ErrorCode:%d    ErrorMessage:%s", dwErrorCode, strErrorMessage);
}


int main()
{
    WSAData wsaData;
    int iErrorNumber = WSAStartup(MAKEWORD(2, 2), &wsaData);

    if (iErrorNumber != 0)
    {
        printf("WSAStartup failed with error: %d\n", iErrorNumber);
        return 1;
    }

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
    {
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
        return 1;
    }
    else
    {
        printf("The Winsock 2.2 dll was found okay\n");
    }

    SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (INVALID_SOCKET == s)
    {
        PrintErrorMessage(GetLastError());
        WSACleanup();
        return 1;
    }

    sockaddr_in sockaddrClient;
    sockaddrClient.sin_family = AF_INET;
    sockaddrClient.sin_port = htons(10086);
    sockaddrClient.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    char buf[MAXBYTE] = "Hello";
    int iResult = sendto(s, buf, MAXBYTE, 0, reinterpret_cast<sockaddr *>(&sockaddrClient), sizeof(sockaddr_in));
    if (iResult == SOCKET_ERROR)
    {
        wprintf(L"sendto failed with error: %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return 1;
    }

    recv(s, buf, MAXBYTE, 0);
    printf("received from server:%s\r\n", buf);

    closesocket(s);
    WSACleanup();

    system("pause");
    return 0;
}

Socket的错误封装

这个错误封装的唯一一个好处就是能够深入的了解一下TCP和UDP的区别。
这个类没有写完整,还差一点儿通讯的功能,实在是写不下去了,以后如果有时间想写的时候再写吧。
里面用到了一些异常处理的方法,其实这些异常是没有必要的,我们可以做一些错误处理就可以了,而没有必要都要抛个异常。
有兴趣的朋友可以将这个类完善一下,从而达到简单通讯的目的。

头文件

#ifndef _SOCKET_H_
#define _SOCKET_H_

#include <exception>
#include <string>
#include <WinSock2.h>
#include <Windows.h>
#include <vector>

#pragma comment(lib, "ws2_32.lib")



namespace PoEdu
{
    class SocketErrorException : public std::exception
    {
    public:
        SocketErrorException(const char *msg, const int errorCode) : std::exception()
        {
            std::string temp = msg;
            temp += std::to_string(errorCode);
            len_ = temp.length() + sizeof(char);
            CopyData(temp.c_str(), len_);
        }
        SocketErrorException(const SocketErrorException &other)
        {
            CopyData(other.msg_, other.len_);
        }
        SocketErrorException operator=(const SocketErrorException &other)
        {
            if (this == &other)
            {
                return *this;
            }

            CopyData(other.msg_, other.len_);
            return *this;
        }

        ~SocketErrorException()
        {
            delete[] msg_;
        }


        virtual char const* what() const
        {
            return msg_;
        }

    private:
        void CopyData(const char *data, const size_t len)
        {
            msg_ = new char[len_];
            strcpy_s(msg_, len_, data);
        }

    private:
        char *msg_;
        size_t len_;
    };


    class Socket
    {
    public:
        enum SocketType
        {
            SOCKETTYPE_UDP,
            SOCKETTYPE_TCP
        };


        Socket(SocketType socketTyp) throw(SocketErrorException);
        ~Socket() throw();

        bool ServerStart(unsigned int port, unsigned maxCount);
        bool ServerStart(sockaddr_in &addr, unsigned maxCount) throw(SocketErrorException);
        bool ServerAccept();
        bool Connect(const char *ip, unsigned int port);
        bool Connect(sockaddr_in &addr);

        bool Send(const char *data, const size_t len);
        bool SendTo(const char *data, const size_t len, sockaddr_in &addr);

        int Recv(char *data, const size_t maxSize);
        int RecvFrom(char *data, const size_t maxSize, sockaddr_in &addr);

    private:
        SOCKET socket_;
        SocketType socketType_;
        bool server_;
        std::vector<SOCKET> vecAcceptSockt_;
    };
}

#endif//_SOCKET_H_

cpp文件

#include "stdafx.h"
#include "Socket.h"
#include <algorithm>


namespace PoEdu
{
    Socket::Socket(SocketType socketTyp) : socketType_(socketTyp), server_(false)
    {
        WSAData wsaData;
        int iErrorCode = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (iErrorCode != 0)
        {
            throw SocketErrorException("WSAStartup failed with errorCode:", iErrorCode);
        }

        if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
        {
            WSACleanup();
            throw SocketErrorException("Could not find a usable version of Winsock.dll. ErrorCode:", wsaData.wVersion);
        }

        int socket_af = AF_INET, sock_type = SOCK_DGRAM, sock_protocal = IPPROTO_UDP;
        if (socketType_ == SOCKETTYPE_TCP)
        {
            sock_type = SOCK_STREAM;
            sock_protocal = IPPROTO_TCP;
        }

        socket_ = socket(socket_af, sock_type, sock_protocal);
        if (socket_ == INVALID_SOCKET)
        {
            WSACleanup();
            throw SocketErrorException("cocket error:", WSAGetLastError());
        }
    }

    Socket::~Socket()
    {
        closesocket(socket_);
        WSACleanup();
    }

    bool Socket::ServerStart(unsigned int port, unsigned maxCount)
    {
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.S_un.S_addr = INADDR_ANY;
        // 127.0.0.1 环路地址
        // 192.168.1.1 LAN网地址
        // 110.110.11.1 上一级网络地址

        return ServerStart(addr, maxCount);
    }

    bool Socket::ServerStart(sockaddr_in& addr, unsigned maxCount)
    {
        bool bRet = false;

        do
        {
            if (::bind(socket_, (sockaddr *)&addr, sizeof(sockaddr_in)) == SOCKET_ERROR)
            {
                break;
            }
            if (socketType_ == SOCKETTYPE_TCP)
            {
                if (::listen(socket_, maxCount) == SOCKET_ERROR)
                {
                    break;
                }
            }

            server_ = true;
            bRet = true;
        } while (false);

        return bRet;
    }

    bool Socket::ServerAccept()
    {
        bool bRet = false;
        if (server_ && socketType_ == SOCKETTYPE_TCP)
        {
            SOCKET s = ::accept(socket_, nullptr, nullptr);
            if (s != SOCKET_ERROR)
            {
                vecAcceptSockt_.push_back(s);
                bRet = true;
            }
        }

        return bRet;
    }

    bool Socket::Connect(const char* ip, unsigned int port)
    {
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.S_un.S_addr = inet_addr(ip);

        return Connect(addr);
    }

    bool Socket::Connect(sockaddr_in& addr)
    {
        bool bRet = false;

        if (socketType_ == SOCKETTYPE_TCP)
        {
            if (::connect(socket_, (sockaddr *)&addr, sizeof(sockaddr_in)) != SOCKET_ERROR)
            {
                bRet = true;
            }
        }

        return bRet;
    }

    bool Socket::Send(const char* data, const size_t len)
    {
        bool bRet = false;

        if (socketType_ == SOCKETTYPE_TCP)
        {
            if (server_)
            {
                // 有可能群聊,也有可能单聊
                // 假设群发
                std::vector<int> vecRet;
                for (auto value : vecAcceptSockt_)
                {
                    vecRet.push_back(::send(value, data, len, 0));
                }
                if (std::find_if(vecRet.begin(), vecRet.end(), [](int result)
                {
                    return result == SOCKET_ERROR;
                }) == vecRet.end())
                {
                    bRet = true;
                }
            }
            else
            {
                if (::send(socket_, data, len, 0) != SOCKET_ERROR)
                {
                    bRet = true;
                }
            }
        }

        return bRet;
    }

    bool Socket::SendTo(const char* data, const size_t len, sockaddr_in &addr)
    {
        bool bRet = true;

        ::sendto(socket_, data, len, 0, (sockaddr *)&addr, sizeof(addr));

        return bRet;
    }

    int Socket::Recv(char* data, const size_t maxSize)
    {
        if (socketType_ == SOCKETTYPE_TCP)
        {
            if (server_)
            {
                int iRet = 0;
                for (auto value : vecAcceptSockt_)
                {
                    // 用多线程,每个线程对应一个客户端
                    iRet += ::recv(value, data, maxSize, 0);
                }
                return iRet;
            }
            else
            {
                return ::recv(socket_, data, maxSize, 0);
            }
        }
    }

    int Socket::RecvFrom(char* data, const size_t maxSize, sockaddr_in& addr)
    {
        return 0;
    }
}

// server -> client 一呼一应
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值