在现代计算机网络中,网络通信是不可或缺的一部分。本文将介绍如何使用C语言实现一个简单的网络通信库,涵盖TCP和UDP协议的基本功能。我们将通过一个示例代码库进行详细讲解,以便更好地理解网络编程的核心概念。
项目结构
本项目包含两个文件:
network.h
:头文件,定义了数据结构和函数原型。network.c
:实现文件,包含具体的网络通信功能。
1. 关键结构体
在network.h
中,我们定义了一个Network
结构体,包含以下字段:
typedef struct Network
{
int type; // 通信协议类型
int sock_fd; // socket描述符
struct sockaddr_in addr; // 通信地址
socklen_t addrlen; // 通信地址字节数
bool issvr; // 是否是服务器
} Network;
2. 初始化网络
init_nw
函数是这个网络库的核心,用于创建socket并初始化地址。根据传入的参数(是否为服务器,协议类型等),该函数执行不同的初始化操作。
Network *init_nw(int type, short port, const char *ip, bool issvr)
{
Network *nw = malloc(sizeof(Network));
nw->sock_fd = socket(AF_INET, type, 0);
if (nw->sock_fd < 0) {
free(nw);
perror("socket");
return NULL;
}
bzero(&nw->addr, nw->addrlen);
nw->type = type;
nw->issvr = issvr;
nw->addr.sin_family = AF_INET;
nw->addr.sin_port = htons(port);
nw->addr.sin_addr.s_addr = inet_addr(ip);
nw->addrlen = sizeof(struct sockaddr_in);
if (issvr) {
if (bind(nw->sock_fd, (SP)&nw->addr, nw->addrlen)) {
free(nw);
perror("bind");
return NULL;
}
if (SOCK_STREAM == type && listen(nw->sock_fd, 50)) {
free(nw);
perror("listen");
return NULL;
}
} else if (SOCK_STREAM == type) { // TCP客户端
if (connect(nw->sock_fd, (SP)&nw->addr, nw->addrlen)) {
free(nw);
return NULL;
}
}
return nw;
}
3. 等待连接
accept_nw
函数用于TCP服务器端,等待客户端的连接请求。它检查当前Network
对象是否为服务器类型,并返回新的连接对象。
Network *accept_nw(Network* svr_nw)
{
if (SOCK_STREAM != svr_nw->type || !svr_nw->issvr) {
printf("只有tcp协议的服务器端的NETWORK对象可以使用");
return NULL;
}
Network *nw = malloc(sizeof(Network));
nw->addrlen = svr_nw->addrlen;
nw->type = SOCK_STREAM;
nw->issvr = true;
nw->sock_fd = accept(svr_nw->sock_fd, (SP)&nw->addr, &nw->addrlen);
if (nw->sock_fd < 0) {
free(nw);
perror("accept");
return NULL;
}
return nw;
}
4. 发送与接收数据
send_nw
和recv_nw
函数分别用于发送和接收数据。根据协议类型,这两个函数会采用不同的方法处理数据。
int send_nw(Network *nw, void* buf, size_t len)
{
if (nw->type == SOCK_DGRAM) {
return sendto(nw->sock_fd, buf, len, 0, (SP)&nw->addr, nw->addrlen);
} else {
return send(nw->sock_fd, buf, len, 0);
}
}
int recv_nw(Network *nw, void* buf, size_t len)
{
if (nw->type == SOCK_DGRAM) {
return recvfrom(nw->sock_fd, buf, len, 0, (SP)&nw->addr, &nw->addrlen);
} else {
return recv(nw->sock_fd, buf, len, 0);
}
}
5. 关闭连接
close_nw
函数用于关闭socket并释放内存,确保资源得到有效管理。
void close_nw(Network *nw)
{
close(nw->sock_fd);
free(nw);
}
6. 获取IP地址
getip_nw
函数用于获取并返回与网络对象关联的IP地址。
const char *getip_nw(Network *nw)
{
return inet_ntoa(nw->addr.sin_addr);
}
总结
通过这种模块化的设计,我们实现了一个简单而强大的网络通信库,易于扩展和维护。用户只需调用高层函数即可实现复杂的网络通信,极大提高了开发效率。这种封装和结构化的写法不仅使代码更易于阅读和理解,还能有效避免常见的错误。希望本文能够为你的网络编程实践提供帮助和启发!
4o
标签:网络通信,return,addr,sock,C语言,Network,fd,nw From: https://blog.csdn.net/qq_50394172/article/details/143103373