上一次小编分享了C++实现网络编程NetWork,这是链接:
C++ 网络通信类 Network 的实现详解-CSDN博客
这次小编带着改进之后的NetWork归来!
在现代计算机网络中,网络通信是不可或缺的一部分。本文将介绍如何使用C语言实现一个简单的网络通信库,涵盖TCP和UDP协议的基本功能。我们将通过一个示例代码库进行详细讲解,以便更好地理解网络编程的核心概念。
1. 类的定义
class NetWork
{
int type; // 通信协议类型
int sock_fd; // socket 描述符
sockaddr_in addr; // 通信地址
int addrlen; // 通信地址字节数
bool issvr; // 是否是服务器
public:
NetWork(void);
NetWork(int type, const char* ip, short port, bool issvr = false);
~NetWork(void);
bool open(void);
NetWork* accept_nw(void);
int send_nw(const char* buf, int flag = 0);
int send_nw(const void* buf, size_t len, int flag = 0);
int recv_nw(void* buf, size_t len, int flag = 0);
};
1.1 成员变量
type
: 代表使用的通信协议类型(如 TCP、UDP)。sock_fd
: 用于标识 socket 的描述符。addr
: 存储通信地址的结构体。addrlen
: 地址结构的大小。issvr
: 布尔值,表示该 socket 是否是一个服务器。
1.2 构造函数与析构函数
NetWork(void)
: 默认构造函数,初始化成员变量。NetWork(int type, const char* ip, short port, bool issvr)
: 带参数的构造函数,用于初始化网络连接。~NetWork(void)
: 析构函数,关闭 socket 并释放资源。
2. 打开连接
2.1 bool open(void)
该方法负责创建 socket 并根据类型执行相应的操作(如绑定、监听或连接)。
bool NetWork::open(void)
{
//创建socket对象
sock_fd = socket(AF_INET,type,0);
if(sock_fd < 0)
{
perror("socket");
return false;
}
//根据type和issvr执行以下流程
if (issvr)
{
// 服务器端绑定和监听
if (bind(sock_fd, (sockaddr*)&addr, addrlen))
{
perror("bind");
return false;
}
if (type == SOCK_STREAM && listen(sock_fd, 50))
{
perror("listen");
return false;
}
}
else if (type == SOCK_STREAM && connect(sock_fd,(sockaddr*)&addr,addrlen))
{
perror("connect");
return false;
}
return true;
}
- 使用
socket
函数创建 socket,返回的描述符存储在sock_fd
中。 - 根据
issvr
和type
,服务器会执行绑定和监听操作,而客户端则尝试连接。
3. 处理连接
3.1 NetWork* accept_nw()
这是一个用于接受连接的函数,只有 TCP 服务器可以调用。
NetWork* NetWork::accept_nw()
{
if (type != SOCK_STREAM || !issvr)
{
puts("只有type为SOCK_STREAM 且为服务端才能调用该函数\n");
}
NetWork* nw = new NetWork;
nw->sock_fd = accept(sock_fd, (sockaddr*)&nw->addr, &nw->addrlen);
if (nw->sock_fd < 0)
{
delete nw;
perror("accept");
return NULL;
}
return nw;
}
- 调用
accept
方法接受客户端连接,并返回一个新的NetWork
对象。
4. 数据传输
4.1 发送数据
send_nw
方法有两个重载,支持发送字符串和自定义长度的缓冲区。
int NetWork::send_nw(const char* buf,int flag )
{
if(type == SOCK_STREAM)
return ::send(sock_fd,buf,strlen(buf)+1,flag);
else
return sendto(sock_fd,buf,strlen(buf)+1,flag,(sockaddr*)&addr,addrlen);
}
int NetWork::send_nw(const void* buf, size_t len,int flag )
{
if (type == SOCK_DGRAM)
{
return sendto(sock_fd, (char*)buf, len, flag, (sockaddr*)&addr, addrlen);
}
else
{
return send(sock_fd,(char*)buf, len, flag);
}
}
- 对于 TCP,使用
send
发送数据。 - 对于 UDP,使用
sendto
发送数据到指定的地址。
4.2 接收数据
recv_nw
方法用于接收数据,支持 TCP 和 UDP。
int NetWork::recv_nw(void* buf, size_t len,int flag )
{
if (type == SOCK_DGRAM)
{
return recvfrom(sock_fd, (char*)buf, len, flag, (sockaddr*)&addr, &addrlen);
}
else
{
return recv(sock_fd, (char*)buf, len, flag);
}
}
- 对于 TCP,使用
recv
接收数据。 - 对于 UDP,使用
recvfrom
从特定地址接收数据。
5. 关键知识点总结
- Socket 编程: 是实现网络通信的基础,Socket 提供了一个接口,用于在网络上发送和接收数据。
- TCP vs UDP: TCP 是面向连接的协议,适用于需要可靠传输的场景;UDP 是无连接的,适合实时性要求高但可以容忍数据丢失的场景。
- 地址结构:
sockaddr_in
是用于存储 IPv4 地址的结构,包含了协议族、端口和 IP 地址。
结语
本文通过分析 NetWork
类的实现,展示了 C++ 中如何进行基础的网络编程。通过封装 socket 的常用操作,开发者可以更方便地进行网络通信。希望本篇文章能帮助读者更好地理解网络编程的基础知识和实践应用。