一、封装
封装基于TCP/IP的TCP以及UDP的客户端以及服务端代码,并制作成共享库
network.h
#ifndef NETWORK_H
#define NETWORK_H
#include <stdio.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
typedef struct Network
{
int type; // 通讯协议的类型
int sock_fd; // socket描述符
struct sockaddr_in addr; // 通讯地址
socklen_t addrlen; // 通讯地址字节数
bool issvr; // 判断是否是服务端
} Network;
typedef struct sockaddr *SP;
// 分配内存,创建socket对象, 初始化地址,绑定、监听、连接
Network *init_network(int type, short port, const char *ip, bool issvr);
// 等待连接,只有type是SCOK_STREAM且是服务端才能调用此函数
Network *accept_network(Network *svr_nw);
// 具备send和sendto的功能
int send_network(Network *nw, void *buf, size_t len);
// 具备recv和recvfrom的功能
int recv_network(Network *nw, void *buf, size_t len);
// 关闭socket对象且释放内存
void close_network(Network *nw);
// 获取IP地址
const char *get_ip(Network *nw);
#endif// NETWORK_H
network.c
#include "network.h"
// 分配内存,创建socket对象, 初始化地址,绑定、监听、连接
Network *init_network(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;
}
// 计算地址结构体的字节数
nw->addrlen = sizeof(struct sockaddr_in);
// 初始化地址结构体
bzero(&nw->addr, nw->addrlen);
// 准备通讯地址
nw->addr.sin_family = AF_INET;
nw->addr.sin_port = htons(port);
nw->addr.sin_addr.s_addr = inet_addr(ip);
nw->type = type;
nw->issvr = issvr;
//是服务器
if(issvr)
{
// 绑定
if(bind(nw->sock_fd, (SP)&nw->addr, nw->addrlen))
{
free(nw);
perror("bind");
return NULL;
}
// TCP服务端 监听
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);
perror("connect");
return NULL;
}
}
return nw;
}
// 等待连接,只有type是SCOK_STREAM且是服务端才能调用此函数
Network *accept_network(Network *svr_nw)
{
if(SOCK_STREAM != svr_nw->type || !svr_nw->issvr)
{
printf("只有type是SCOK_STREAM且是服务端才能调用此函数\n");
return NULL;
}
// 为新的network分配内存,并初始化
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;
}
// 具备send和sendto的功能
int send_network(Network *nw, void *buf, size_t len)
{
if(SOCK_DGRAM == nw->type)
{
return sendto(nw->sock_fd, buf, len, 0, (SP)&nw->addr, nw->addrlen);
}
else
{
return send(nw->sock_fd, buf, len, 0);
}
}
// 具备recv和recvfrom的功能
int recv_network(Network *nw, void *buf, size_t len)
{
if(SOCK_DGRAM == nw->type)
{
return recvfrom(nw->sock_fd, buf, len, 0, (SP)&nw->addr, &nw->addrlen);
}
else
{
return recv(nw->sock_fd, buf, len, 0);
}
}
// 关闭socket对象且释放内存
void close_network(Network *nw)
{
close(nw->sock_fd);
free(nw);
}
// 获取IP地址
const char *get_ip(Network *nw)
{
return inet_ntoa(nw->addr.sin_addr);
}
二、TCP测试
TCP客户端
#include <stdio.h>
#include <string.h>
#include "network.h"
int main(int argc , const char* argv[])
{
Network *nw = init_network(SOCK_STREAM, atoi(argv[2]), argv[1], false);
if(NULL == nw)
{
perror("init_network");
exit(1);
}
char buf[4096] = {};
size_t buf_size = sizeof(buf);
while(1)
{
printf(">>>");
scanf("%s", buf);
int ret = send_network(nw, buf, strlen(buf)+1);
if(ret <= 0)
{
printf("通讯结束\n");
break;
}
ret = recv_network(nw, buf, buf_size);
if(ret <= 0)
{
printf("通讯结束\n");
break;
}
printf("recv:%s\n", buf);
}
close_network(nw);
return 0;
}
TCP服务端
#include <stdio.h>
#include <string.h>
#include "network.h"
int main(int argc , const char* argv[])
{
Network *srv_nw = init_network(SOCK_STREAM, atoi(argv[2]), argv[1], true);
if(NULL == srv_nw)
{
perror("init_network");
exit(1);
}
Network *clt_nw = NULL;
do
{
clt_nw = accept_network(srv_nw);
if(clt_nw == NULL)
{
perror("accept_network error");
exit(1);
}
}while(fork());
// 子进程执行到此
char buf[4096] = {};
size_t buf_size = sizeof(buf);
while(1)
{
int ret = recv_network(clt_nw, buf, buf_size);
if(ret <= 0)
{
printf("通讯结束\n");
break;
}
printf("recv:%s\n", buf);
ret = send_network(clt_nw, buf, strlen(buf)+1);
if(ret <= 0)
{
printf("通讯结束\n");
break;
}
}
close_network(srv_nw);
return 0;
}
测试
1.编译
gcc TCPserver.c network.c -o s
gcc TCPclient.c network.c -o c
2.运行服务端
./s 192.168.159.138 8888 // 192.168.159.138服务端(本机)ip 8888设置端口号(0~65535)
这里使用本机作为服务端
3.运行客户端
./s 192.168.159.138 8888 // 192.168.159.138服务端ip 8888服务端设置端口号
三、制作共享库
制作共享库命令:
1、gcc -fpic -c network.c // 编译出目标文件
2、gcc -shared -fpic network.o -o libnw.so // 打包目标文件生成共享库
3、sudo cp libnw.so /usr/lib
4、sudo cp network.h /usr/include/
使用:
gcc code.c -lnw