封装TCP\UDP通用通信代码库

一、封装

封装基于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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值