C++小工具封装 —— NetWork(TCP、UDP)

在之前的文章中我们介绍到也写到基于TCP和UDP协议的网络通信。本篇我们又闲得无聊把这俩给封装成一个小工具以满足实际应用时多功能网络服务器的需要。

这个NetWork小工具是在Windows下制作的所以别忘了该有的头文件。C++中编写我们就遵循面向对象的思想来。

cs 复制代码
#ifndef NETWORK_H
#define NETWORK_H

#include <iostream>
#include <sys/types.h>
// #include <sys/socket.h>
// #include <netinet/in.h>
// #include <arpa/inet.h>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

class NetWork
{
    int sock;           //socket对象描述符
    int type;           //协议类型
    sockaddr_in addr;   //通信地址
    socklen_t addrlen;  //地址结构字节数
    bool is_svr;        //是否为服务器端
public:
    NetWork(void);
    NetWork(int type,const char *ip,short port,bool is_svr=false);
    ~NetWork(void);
    bool open(void);
    NetWork* accept(void);
    int send(const char *buf,int flag=0);
    int send(const void *buf,size_t len,int flag=0);
    int recv(void *buf,size_t len,int flag=0);
};


#endif // NETWORK_H

这里我们要特别注意,在Linux和Windows下进行网络编程包含的头文件有所区别,如下注释掉的是Linux下所包含的头文件,Windows下编程需要加上下面三行头文件:

cs 复制代码
// #include <sys/socket.h>
// #include <netinet/in.h>
// #include <arpa/inet.h>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>

接着来完成定义:

cpp 复制代码
#include "network.h"
using namespace std;

NetWork::NetWork(void)
{
    addrlen = sizeof(addr);
    type = SOCK_STREAM;
    is_svr = false;
}

NetWork::NetWork(int type, const char *ip, short port, bool is_svr):type(type), is_svr(is_svr)
{
    // 不在构造函数中创建socket,因为socket创建可能失败,而构造函数是没有返回值的,不能在此创建
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip);
    addrlen = sizeof(addr);
}

NetWork::~NetWork(void)
{
    close(sock);
}

bool NetWork::open(void)
{
    WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		perror("WSADATA失败");
	}
    //创建socket对象
    sock = socket(AF_INET, type, 0);
    if (sock < 0)
    {
        perror("socket");
        return false;
    }
    //根据type和is_svr执行以下流程
    if(is_svr)
    {
        if(bind(sock, (sockaddr*)&addr, addrlen))
        {
            perror("bind");
            return false;
        }
        if(SOCK_STREAM == type && listen(sock, 50))
        {
            perror("listen");
            return false;
        }
    }
    else if(SOCK_STREAM == type && connect(sock, (sockaddr*)&addr, addrlen))
    {
        perror("connect");
        return false;
    }
    return true;
}

NetWork *NetWork::accept(void) 
{
    if(SOCK_STREAM!= type || !is_svr)
    {
        puts("只有type为SOCK_STREAM且为服务端才能调用该函数\n");
        return NULL;
    }

    NetWork *nw = new NetWork;
    nw->sock = ::accept(sock, (sockaddr*)&nw->addr, &nw->addrlen);
    if(nw->sock < 0)
    {
        perror("accept");
        delete nw;
        return NULL;
    }
    return nw;
}

int NetWork::send(const char *buf, int flag) 
{
    if(SOCK_STREAM == type)
         return ::send(sock, buf, strlen(buf)+1, flag);
    else
         return sendto(sock, buf, strlen(buf)+1, flag, (sockaddr*)&addr, addrlen);
}

int NetWork::send(const void *buf, size_t len, int flag) 
{
    if(SOCK_STREAM == type)
        return ::send(sock, (const char*)buf, len, flag);
    else
        return sendto(sock, (const char*)buf, len, flag, (sockaddr*)&addr, addrlen);
}

int NetWork::recv(void *buf, size_t len, int flag) 
{
    if(SOCK_STREAM == type)
        return ::recv(sock, (char*)buf, len, flag);
    else
        return recvfrom(sock, (char*)buf, len, flag, (sockaddr*)&addr, &addrlen);
}

细心的你应该可以发现,我们Windows下写的函数定义好像和上一篇Linux下写的有点区别:

cpp 复制代码
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
	perror("WSADATA失败");
}

可以发现,我们在创建socket套接字之前有这么几行陌生的代码。这段代码的作用是初始化 Windows Socket API。在使用网络编程之前,需要先调用 WSAStartup 来初始化 Winsock DLL。

over

相关推荐
软行1 小时前
LeetCode 每日一题 3876. 构造奇偶一致的数组 II
c++·算法·leetcode
繁星蓝雨1 小时前
C++设计原理———重载(extern “C“的由来、顺序依赖、语义依赖、overload、名称修饰符、对象操作、运算符重载、新增运算符、枚举和布尔类型)
c语言·c++·extern c·overload·重载·语义依赖·顺序依赖
handler011 小时前
【Linux】虚拟地址空间解析
linux·运维·c++·线程·进程·虚拟地址空间·虚拟地址
(Charon)1 小时前
【C++】网络缓冲区设计(二):Ring Buffer环形缓冲区、head/tail与跨界读写
开发语言·c++
码匠许师傅2 小时前
【设计模式精讲】24.观察者模式(Observer)
c++·观察者模式·设计模式·uml
imgsq2 小时前
S-57 数据解剖:把一个 ENC 文件拆给你看
c++·数据可视化
迷茫、Peanut2 小时前
中断的时钟
c++
2402_882893862 小时前
用哈希表封装 unordered_map 和 unordered_set —— 手撕 C++ 哈希容器
c++·哈希桶·unordered_map·unordered_set
熊猫钓鱼>_>3 小时前
用 OHAudioSuite 空间渲染节点搭一座「3D 有声博物馆」——从三种模式到 FreeBuds 头追的实战记录
c++·3d·ai·harmonyos·arkts·audio·ohaudiosuite
_约书亚_3 小时前
chapter 9 高级线程管理 — 归纳总结
c++