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;
int sock_fd;
struct sockaddr_in addr;
socklen_t addrlen;
bool is_srv;
}NetWork;
typedef struct sockaddr* SP;
NetWork* init_nw(int type,const char* ip,short port,bool is_srv);
NetWork* accept_nw(NetWork* nw);
int send_nw(NetWork* nw,const void* buf,size_t len);
int recv_nw(NetWork* nw,void* buf,size_t len);
void close_nw(NetWork* nw);
#endif
network.c:
#include "network.h"
#define handle_error(msg)\
do{perror(msg);free(nw);return NULL;}while(0)
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);
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");
}
}
if(nw->type == SOCK_STREAM && nw->is_srv)
{
if(0 > listen(nw->sock_fd,20))
{
handle_error("listen");
}
}
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;
}
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)
{
perror("accept");
free(new);
return NULL;
}
return new;
}
return NULL;
}
int send_nw(NetWork* nw,const void* buf,size_t len)
{
int ret;
if(nw->type == SOCK_STREAM)
{
ret = send(nw->sock_fd,buf,len,0);
}
else
{
ret = sendto(nw->sock_fd,buf,len,0,(SP)&(nw->addr),nw->addrlen);
}
return ret;
}
int recv_nw(NetWork* nw,void* buf,size_t len)
{
int ret;
if(nw->type == SOCK_STREAM)
{
ret = recv(nw->sock_fd,buf,len,0);
}
else
{
ret = recvfrom(nw->sock_fd,buf,len,0,(SP)&(nw->addr),&(nw->addrlen));
}
return ret;
}
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.c 和network.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 就可以正常编译了
|