封装tcp和udp网络通信

tcp和udp网络通信的封装

在写项目的时候,我们发现,tcp和udp的网络通信模型有很多的相似之处,因此我们可以考虑将其封装成一个函数,集成相关的函数,方便我们后面项目的使用。

代码展示:

network.h:

#ifndef NETWORK_H
#define NETWORK_H

#include <stdbool.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>

typedef struct NetWork
{
	int type;					//通信协议的类型 SOCK_STREAM SOCK_DGRAM
	int sock_fd;				//socket描述符
	struct sockaddr_in addr;	//通信地址
	socklen_t addrlen;			//结构体字节数
	bool is_srv;				//是否是服务端
}NetWork;

typedef struct sockaddr* SP;

//分配内存,创建socket,准备地址,绑定,监听,连接
NetWork* init_nw(int type,const char* ip,short port,bool is_srv);
//等待连接,只有tcp服务端可以用,SOCK_STREAM
NetWork* accept_nw(NetWork* nw);
//具备send和sendto的发送函数
int send_nw(NetWork* nw,const void* buf,size_t len);
//具备recv和recvform的接收函数
int recv_nw(NetWork* nw,void* buf,size_t len);
//关闭socket并且释放内存
void close_nw(NetWork* nw);

#endif

network.c:

/**************************************************
>	作	  者:杭电羊皮卷
>   文件名称: network.c
>   创建日期:2022年09月07日
>   描    述:网络通信的封装tcp和udp
**************************************************/

#include "network.h"

#define handle_error(msg)\
	do{perror(msg);free(nw);return NULL;}while(0)

//分配内存,创建socket,准备地址,绑定,监听,连接
NetWork* init_nw(int type,const char* ip,short port,bool is_srv)
{
	NetWork* nw = (NetWork* )malloc(sizeof(NetWork));
	nw->type = type;
	nw->is_srv = is_srv;
	nw->addrlen = sizeof(struct sockaddr_in);
	//创建socket
	nw->sock_fd = socket(AF_INET,type,0);
	if(nw->sock_fd < 0)
	{
		handle_error("socket");
	}
	//准备通信地址
	nw->addr.sin_family = AF_INET;
	nw->addr.sin_port = htons(port);
	nw->addr.sin_addr.s_addr = inet_addr(ip);

	//只有服务器才绑定
	if(is_srv)
	{
		if(0 > bind(nw->sock_fd,(SP)&(nw->addr),nw->addrlen))
		{
			handle_error("bind");
		}
	}
	//监听 服务器tcp才监听
	if(nw->type == SOCK_STREAM && nw->is_srv)
	{
		if(0 > listen(nw->sock_fd,20))
		{
			handle_error("listen");
		}
	}
	//连接,只有tcp的客户端才连接
	if(nw->is_srv == 0 && type == SOCK_STREAM)
	{
		int ret = connect(nw->sock_fd,(SP)&nw->addr,nw->addrlen);
		if(ret < 0)
		{
			handle_error("connect");
		}
	}
	return nw;
}
//等待连接,只有tcp服务端可以用,SOCK_STREAM
NetWork* accept_nw(NetWork* nw)
{
	if(nw->type == SOCK_STREAM && nw->is_srv)
	{
		NetWork* new = (NetWork* )malloc(sizeof(NetWork));
		new->type = nw->type;
		new->is_srv = true;
		new->addr = nw->addr;
		new->addrlen = nw->addrlen;
		new->sock_fd = accept(nw->sock_fd,(SP)&nw->addr,&(nw->addrlen));
		if(new->sock_fd < 0)
		{
			//handle_error("accept");
			perror("accept");
			free(new);
			return NULL;
		}
		return new;
	}
	return NULL;
}
//具备send和sendto的发送函数
int send_nw(NetWork* nw,const void* buf,size_t len)
{
	int ret;
	if(nw->type == SOCK_STREAM)
	{
		//tcp的发送
		ret = send(nw->sock_fd,buf,len,0);
	}
	else
	{
		//udp的发送
		ret = sendto(nw->sock_fd,buf,len,0,(SP)&(nw->addr),nw->addrlen);
	}
	return ret;
}
//具备recv和recvform的接收函数
int recv_nw(NetWork* nw,void* buf,size_t len)
{
	int ret;
	if(nw->type == SOCK_STREAM)
	{
		//tcp
		ret = recv(nw->sock_fd,buf,len,0);
	}
	else
	{
		ret = recvfrom(nw->sock_fd,buf,len,0,(SP)&(nw->addr),&(nw->addrlen));
	}
	return ret;
}
//关闭socket并且释放内存
void close_nw(NetWork* nw)
{
	close(nw->sock_fd);
	free(nw);
}

制作动态库:

首先我们考虑在用户主目录中创建两个目录,一个用于存放自己制作的动态库,一个用来存放在自己的头文件,所以在命令行中输入以下两个命令。

mkdir ~/lib

mkdir ~/include

其中lib用来存放动态库文件(.so文件),include存放头文件(.h文件)

然后添加这两个文件加进环境变量中

输入vim ~/.bashrc,这个文件是系统的配置文件,切记不要去修改,按下大写的G直接跳转到文末,然后按i进入插入模式,输入以下几行命令

export LIBRARY_PATH=$LIBRARY_PATH:/home/ubuntu/lib			//添加静态库查找路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ubuntu/lib	//添加动态库加载路径
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/home/ubuntu/include	//添加头文件查找路径

然后ctrl+c退出编辑模式,大写的两个Z退出文件

输入命令source ~/.bashrc该命令可以使系统配置文件立即生效

一切准备工作就绪,接下来制作动态库,将工作目录调整到network.cnetwork.h所在路径

先后输入命令

gcc -c -fpic network.c

gcc -shared network.o -o libnw.so

然后用ls -l命令查看可以看到多了一个可执行文件

libnw.so文件复制到~/lib文件

network.h文件复制到~/include文件

cp libnw.so ~/lib

cp network.h ~/include

然后就可以使用该库文件啦,使用方式和数学库一样的,在进行gcc编译的时候需要加载库文件

如:gcc main.c -lnw就可以正常编译了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值