C提高——模拟服务器接收和发送案例

模拟服务器接受和发送案例

/*
 *运行平台:Win10,Visual Studio 2015
 *参考资料:《C Primer plus 第六版》,传智扫地增C提高课程
*/

目录

  • 模拟服务器接受和发送案例
    • 一、何为动态库
      • 1、动态库
      • 2、静态库
      • 3、二者区别
    • 二、实现功能
    • 三、初步搭建动态库
      • 1、新建socketclient工程,应用程序类型为DLL
      • 2、新建socketclient.c文件
      • 3、在Debug模式下编译工程
    • 三、初步搭建测试框架
      • 1、新建动态测试框架工程
      • 2、添加dll、lib文件
    • 四、完善
      • 1、完善main.c
      • 2、完善socketclient.c


一、何为动态库

1、动态库

  动态链接库,英文为DLL,是Dynamic Link Library 的缩写形式,DLL是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件
  动态库在程序编译时并不会被链接到目标文件中,而是在程序运行时才会被载入不同的应用程序如果需要调用相同的库,那么内存只需要有一份该共享库的实例

2、静态库

  静态链接库,英文名LIB,在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中的这种库

3、二者区别

动态库 静态库
生成阶段 链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用 在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系
内容 包含实际的函数和数据 一般是一些索引信息,记录了DLL中函数的入口和位置

  使用动态链接时:应用程序会使用LIB文件链接到DLL 文件。在应用程序的可执行文件中存放的不是被调用的函数代码,而是DLL中相应函数代码的地址,从而节省了内存资源
  所以在使用动态链接时会同时需要到lib文件和dll文件

二、实现功能

  通过调用动态库,模拟服务器接受和发送数据,并以文件日志的方式打印错误信息。

三、初步搭建动态库

1、新建socketclient工程,应用程序类型为DLL

如图所示:

C提高——模拟服务器接收和发送案例_第1张图片

2、新建socketclient.c文件

代码如下:
需要添加__declspec(dllexport),才可以使动态库中的函数导出,即在外部程序中使用动态库的函数

#define  _CRT_SECURE_NO_WARNINGS 
#include 
#include 
#include 
	
//客户端初始化 获取handle上下
__declspec(dllexport)
int cltSocketInit(void **handle /*out*/)
{
	return 0;
}

//客户端发报文
__declspec(dllexport)
int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/)
{
	return 0;
}

//客户端收报文
__declspec(dllexport)
int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/)
{
	return 0;
}

//客户端释放资源
__declspec(dllexport)
int cltSocketDestory(void *handle/*in*/)
{
	return 0;
}

3、在Debug模式下编译工程

此时,在工程文件中的Debug目录下可以找到如下dlllib文件

C提高——模拟服务器接收和发送案例_第2张图片

三、初步搭建测试框架

1、新建动态测试框架工程

添加main.c和socketclientdll.h文件
socketclientdll.h内容如下:

#ifndef _INC_Demo01_H
#define _INC_Demo01_H

#ifdef  __cplusplus
extern "C" {
#endif
	
//------------------第一套api接口---Begin--------------------------------//
//客户端初始化 获取handle上下
int cltSocketInit(void **handle /*out*/); 
	
//客户端发报文
int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/,  int buflen /*in*/);
	
//客户端收报文
int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/);
	
//客户端释放资源
int cltSocketDestory(void *handle/*in*/);
//------------------第一套api接口---End-----------------------------------//
	
	
//------------------第二套api接口---Begin--------------------------------//
//客户端初始化 获取handle上下
int cltSocketInit2(void **handle); 

//客户端发报文
int cltSocketSend2(void *handle, unsigned char *buf,  int buflen);

//客户端收报文
int cltSocketRev2(void *handle, unsigned char **buf, int *buflen);


int cltSocketRev2_Free(unsigned char **buf);

//客户端释放资源
int cltSocketDestory2(void **handle);
//------------------第二套api接口---End--------------------------------//
	
#ifdef  __cplusplus
}
#endif

#endif  /* _INC_Demo01_H */

main.c内容如下:

#define  _CRT_SECURE_NO_WARNINGS 
#include 
#include 
#include 
#include "socketclientdll.h"

int main()
{
	int *handle = NULL;

	cltSocketInit(&handle);
	system("pause");
	return 0;
}

2、添加dll、lib文件

  1. 把刚才生成的dlllib文件放到新建工程的main.c同级目录

C提高——模拟服务器接收和发送案例_第3张图片

  1. 添加socketlient.lib依赖

C提高——模拟服务器接收和发送案例_第4张图片

通过上述步骤,可以初步搭建一个测试框架进行测试,下面来完善部分C文件。

四、完善

1、完善main.c

第一套API函数

int main()
{
	unsigned char inbuf[12] = "12345";
	unsigned char outbuf[12] = { "0" };
	int		inbuflen;
	int		ret;
	int		outbuflen;
	void	*handle = NULL;

	inbuflen = strlen(inbuf);
	
	//	1、初始化
	ret = cltSocketInit(&handle/*out*/);
	if (ret != 0)
	{
		return ret;
	}

	//	2、发送报文
	ret = 0;
	ret = cltSocketSend(handle, inbuf, inbuflen);
	if (ret != 0)
	{
		return ret;
	}

	//	3、接受报文
	ret = 0;
	ret = cltSocketRev(handle, outbuf, &outbuflen);
	if (ret != 0)
	{
		return ret;
	}

	//	4、释放资源
	ret = 0;
	ret = cltSocketDestory(handle);
	if (ret != 0)
	{
		return ret;
	}
	handle = NULL;	//避免野指针

	system("pause");
	return 0;
}

使用第二套API函数所用到的main函数

int main()
{
		unsigned char *outbuf = NULL;
	unsigned char inbuf[12] = "12345";
	int		inbuflen;
	int		outbuflen;
	int		ret;
	void	*handle = NULL;

	inbuflen = strlen(inbuf);
	
	//	1、初始化
	ret = cltSocketInit2(&handle);
	if (ret != 0)
	{
		return ret;
	}

	//	2、客户端发报文
	ret = 0;
	ret = cltSocketSend2(handle, inbuf, inbuflen);
	if (ret != 0)
	{
		return ret;
	}

	//	3、客户端收报文
	ret = 0;
	ret = cltSocketRev2(handle, &outbuf, &outbuflen);
	if (ret != 0)
	{
		return ret;
	}

	//	4、客户端释放资源
	ret = 0;
	ret = cltSocketRev2_Free(&outbuf);
	if (ret != 0)
	{
		return ret;
	}

	ret = 0;
	ret = cltSocketDestory2(&handle);
	if (ret != 0)
	{
		return ret;
	}

	system("pause");
	return 0;
}

2、完善socketclient.c

#define  _CRT_SECURE_NO_WARNINGS 
#include 
#include 
#include 
#include "itcastlog.h"

//定义结构体变量进行数据类型封装:ip,version,port,*p,plen
typedef struct SCK_HANDLE
{
	char	verision[64];
	char	ip[128];
	int		port;
	unsigned char	*p;
	int		plen;
}SCK_HANDLE;

//------------------第一套api接口---Begin--------------------------------//

//客户端初始化 获取handle上下
__declspec(dllexport)
int cltSocketInit(void **handle /*out*/)
{	
	SCK_HANDLE *sck = NULL;
	int		ret;

	/* 判断参数 */
	if (handle == NULL)
	{
		ret = -1;											
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func cltSocketInit() err:%d  handle == NULL\n" ,ret);
		return ret;
	}

	sck = (SCK_HANDLE *)malloc(sizeof(SCK_HANDLE));//开辟内存
	if (sck == NULL)
	{
		ret = -2;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func cltSocketInit() err:%d", ret);
		return ret;
	}

	memset(sck, 0, sizeof(SCK_HANDLE));	

	/* 信息赋值 */
	strcpy(sck->ip, "192.168.191.1");
	strcpy(sck->verision, "version 1.0");
	sck->port = 8081;

	*handle = sck;

	return 0;
}

//客户端发报文
__declspec(dllexport)
int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/)
{
	SCK_HANDLE *sck = NULL;
	int ret;

	/* 判断参数 */
	if (handle == NULL || buf == NULL )
	{
		ret = -1;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func cltSocketSend() err:%d handle == NULL || buf == NULL || buflen == NULL\n", ret);//日志的形式打印错误信息
		return ret;
	}

	/* 申请内存 */
	sck = (SCK_HANDLE*)malloc(sizeof(SCK_HANDLE));
	if (sck == NULL)
	{
		ret = -2;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func  cltSocketSend() err:%d (SCK_HANDLE*)malloc(sizeof(SCK_HANDLE)) fail\n", ret);//日志的形式打印错误信息
		return ret;
	}

	/* 申请内存 */
	sck->p = (unsigned char *)malloc(buflen*sizeof(unsigned char));
	if ((sck->p)==NULL)
	{
		ret = -3;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func  cltSocketSend() err:%d (unsigned char *)malloc(buflen*sizeof(unsigned char)) fail\n", ret);//日志的形式打印错误信息
		return ret;
	}

	memcpy(sck->p, buf, buflen);	//以内存块的方式复制
	sck->plen = buflen;

	return 0;
}

//客户端收报文
__declspec(dllexport)
int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/)
{
	SCK_HANDLE *sck = NULL;
	int ret;

	if (handle == NULL || buf == NULL || buflen == NULL)
	{
		ret = -1;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func cltSocketRev() err:%d handle == NULL || buf == NULL || buflen == NULL\n", ret);//日志的形式打印错误信息
		return ret;
	}

	sck = (SCK_HANDLE *)handle;

	memcpy(buf, sck->p, sck->plen);
	*buflen = sck->plen;

	return 0;
}

//客户端释放资源
__declspec(dllexport)
int cltSocketDestory(void *handle/*in*/)
{
	SCK_HANDLE *sck = NULL;
	int ret;

	if (handle == NULL)
	{
		ret = -1;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func cltSocketDestory() err:%d handle == NULL\n",ret);//日志的形式打印错误信息
		return ret;
	}

	sck = (SCK_HANDLE *)handle;
	if (sck->p)
	{
		free(sck->p);
		sck->p = NULL;
	}
	
	free(sck);

	return 0;
}

//------------------第二套api接口---Begin--------------------------------//
__declspec(dllexport)
int cltSocketInit2(void **handle/*out*/)
{
	return cltSocketInit(handle);
}

//客户端发报文
__declspec(dllexport)
int cltSocketSend2(void *handle/*in*/, unsigned char *buf/*in*/, int buflen/*in*/)
{
	return cltSocketSend(handle,buf,buflen);
}
//客户端收报文
__declspec(dllexport)
int cltSocketRev2(void *handle, unsigned char **buf, int *buflen)
{
	SCK_HANDLE *sck = NULL;
	int ret;
	unsigned char *tmp = NULL;

	if (handle == NULL || buf == NULL || buflen == NULL)
	{
		ret = -1;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func cltSocketRev() err:%d handle == NULL || buf == NULL || buflen == NULL\n", ret);//日志的形式打印错误信息
		return ret;
	}
	sck = (SCK_HANDLE *)handle;

	tmp = (unsigned char*)malloc(sck->plen);
	if (tmp == NULL)
	{
		ret = -2;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func cltSocketRev() err:%d (unsigned char*)malloc(*buflen)\n", ret);//日志的形式打印错误信息
		return ret;
	}
	memset(tmp, 0, sck->plen);

	memcpy(tmp, sck->p, sck->plen);
	*buflen = sck->plen;
	*buf = tmp;

	return 0;
}

//客户端释放资源
__declspec(dllexport)
int cltSocketRev2_Free(unsigned char **buf)
{
	int ret;

	if (buf == NULL)
	{
		ret = -1;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func cltSocketRev2_Free() err:%d buf == NULL\n",ret);//日志的形式打印错误信息
		return ret;
	}

	free(*buf);
	
	*buf = NULL;

	return 0;
}

//客户端释放资源
__declspec(dllexport)
int cltSocketDestory2(void **handle)
{
	SCK_HANDLE *sck = NULL;
	int ret;

	if (handle == NULL)
	{
		ret = -1;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret,"func cltSocketDestory() err:%d handle == NULL\n", ret);//日志的形式打印错误信息
		return ret;
	}

	sck = (SCK_HANDLE *)(*handle);
	if (sck->p)
	{
		free(sck->p);
		sck->p = NULL;//避免野指针
	}

	free(sck);
	*handle = NULL;

	return 0;
}

你可能感兴趣的:(C语言提高篇,dll,堆栈,c语言)