当前位置:   article > 正文

数码相框(十五、电子书支持远程打印)_电子相框

电子相框

注:本人已购买韦东山老师第三期项目视频,内容来源《数码相框项目视频》,只用于学习记录,如有侵权,请联系删除。

这一节我们继续修改电子书的源码,让电子书既能够通过标准输出打印,也能通过网络远程打印,代码框架如下图所示:

如上图所示:

  • 我们仿照之前的代码框架,使用 debug_manager.c 管理 stdout.c 和 netprint.c,在 stdout.c 和 netprint.c 中分别使用 RegisterDebugOpr 函数向上注册 T_DebugOpr 结构体,T_DebugOpr 结构体的代码如下:

    typedef struct DebugOpr{
    	char *name;
    	int isCanUsed;
    	int (*DebugInit)(void);
    	int (*DebugExit)(void);
    	int (*DebugPrint)(char *strData);
    	struct DebugOpr *ptNext;
    }T_DebugOpr, *PT_DebugOpr;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 要实现的功能:

    • ① 其他文件调用DebugPrint函数打印;
    • ② DebugPrint 函数调用底层的结构体来打印,即调用 stdout.c 和 netprint.c提供的打印函数来打印;
    • ③ 可以选择是否从某个渠道(stdout.c或者netprint.c)打印;
    • ④ 对于netprint.c数据应该先存入一个buffer,然后当客户端连接之后,再用网络通信传出;
    • ⑤ 每条信息都有打印级别,可以设置要打印的级别。

1.接下来,我们仿照之前的 display_manager.c 编写 debug_manager.c,debug_manager.c 的代码如下:

#include <debug_manager.h>
#include <config.h>
#include <string.h>
#include <stdio.h>

static PT_DebugOpr g_ptDebugOprHead = NULL;

int RegisterDebugOpr(PT_DebugOpr ptDebugOpr)
{
   PT_DebugOpr ptCur;
   
   if (!g_ptDebugOprHead)
   {
   	g_ptDebugOprHead   = ptDebugOpr;
   	ptDebugOpr->ptNext = NULL;
   }
   else
   {
   	ptCur = g_ptDebugOprHead;
   	while (ptCur->ptNext)
   	{
   		ptCur = ptCur->ptNext;
   	}
   	ptCur->ptNext = ptDebugOpr;
   	ptDebugOpr->ptNext = NULL;
   }
   
   return 0;
}


void ShowDebugOpr(void)
{
   PT_DebugOpr ptCur;
   int i = 0; 
   
   if (!g_ptDebugOprHead)
   {
   	printf("don't have InputOpr\n");
   	return;
   }
   else
   {
   	ptCur = g_ptDebugOprHead;
   	do{
   		printf("%02d %s\n", i++, ptCur->name);
   		ptCur = ptCur->ptNext;
   	}while(ptCur);
   }
}

PT_DebugOpr GetDebugOpr(char *pcName)
{
   PT_DebugOpr ptCur;
   
   if (!g_ptDebugOprHead)
   {
   	return NULL;
   }
   else
   {
   	ptCur = g_ptDebugOprHead;
   	do
   	{
   		if (strcmp(ptCur->name, pcName) == 0)
   			return ptCur;
   		else
   			ptCur = ptCur->ptNext;
   	}
   	while (ptCur);	
   }
   return NULL;
}

int DebugInit(void)
{
   int iError;

   iError = StdoutInit();
   iError |= NetPrintInit();
   return iError;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

2.stdout.c 的代码如下:

#include <debug_manager.h>
#include <stdio.h>
#include <string.h>

static int StdoutDebugPrint(char *strData)
{
	/* 直接把输入信息使用printf打印出来 */
	printf("%s\n", strData);
	return strlen(strData);
}

static int StdoutDebugInit(void)
{
	return 0;
}

static int StdoutDebugExit(void)
{
	return 0;
}

static T_DebugOpr g_tStdoutDebugOpr = {
	.name       = "stdout",
	.isCanUsed  = 1,
	.DebugInit  = StdoutDebugInit,
	.DebugExit  = StdoutDebugExit,
	.DebugPrint = StdoutDebugPrint,
};


int StdoutInit(void)
{
	return RegisterDebugOpr(&g_tStdoutDebugOpr);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

3.netprint.c 的代码如下:

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


#define SERVER_PORT 5678
#define PRINT_BUF_SIZE (16*1024)

static int g_iSocketServer;
static struct sockaddr_in g_tSocketServerAddr;
static struct sockaddr_in g_tSocketClientAddr;
static int g_iHaveConnected = 0;  /* 标记是否连接上,0:没连接上;1:已经连接上 */

static char *g_pcNetPrintBuf;

static int g_iReadPos  = 0;
static int g_iWritePos = 0;

static pthread_t g_tSendThreadID;
static pthread_t g_tRecvThreadID;

static pthread_mutex_t g_tNetDebugSendMutex  = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  g_tNetDebugSendConVar = PTHREAD_COND_INITIALIZER;


/* 判断环形缓冲区是否满
 * 返回值:1:满;0:不满
 */
static int isFull(void)
{
	return (((g_iWritePos + 1) % PRINT_BUF_SIZE) == g_iReadPos);
}

/* 判断环形缓冲区是为空
 * 返回值:1:为空;0:不为空
 */
static int isEmpty(void)
{
	return (g_iWritePos == g_iReadPos);
}

static int PutData(char cVal)
{
	if (isFull())
	{
		return -1;
	}
	else
	{
		g_pcNetPrintBuf[g_iWritePos] = cVal;
		g_iWritePos = (g_iWritePos + 1) % PRINT_BUF_SIZE;
		return 0;
	}
}
	
static int GetData(char *pcVal)
{
	if (isEmpty())
	{
		return -1;
	}
	else
	{
		*pcVal = g_pcNetPrintBuf[g_iReadPos];
		g_iReadPos = (g_iReadPos + 1) % PRINT_BUF_SIZE;
		return 0;
	}
}


static void *NetDebugSendThreadFunction (void *pVoid)
{
	char strTmpBuf[512];
	char cVal;
	int i;
	int iAddrLen;
	int iSendLen;
	while (1)
	{
		/* 平时处于休眠状态 */
		pthread_mutex_lock(&g_tNetDebugSendMutex);
		pthread_cond_wait(&g_tNetDebugSendConVar, &g_tNetDebugSendMutex);
		pthread_mutex_unlock(&g_tNetDebugSendMutex);
		while ((g_iHaveConnected == 1) && (!isEmpty()))
		{
			i = 0;

			/* 把环形缓冲区的数据取出来,最多取512字节 */
			while ((i < 512) && (GetData(&cVal) == 0))
			{
				strTmpBuf[i] = cVal;
				i++;
			}
			strTmpBuf[i] = '\0';
			
			/* 执行到这里表示被唤醒 */
			/* 把环形缓冲区的数据取出来用sendto函数发送打印信息给客户端 */
			iAddrLen = sizeof(struct sockaddr);
			iSendLen = sendto(g_iSocketServer, strTmpBuf, i, 0, (const struct sockaddr *)&g_tSocketClientAddr, iAddrLen);
		}
		
	}

	return NULL;
}

static void *NetDebugRecvThreadFunction (void *pVoid)
{
	int iRecvLen;
	unsigned char ucRecvBuf[1000];
	socklen_t iAddrLen;
	struct sockaddr_in tSocketClientAddr;
	
	while (1)
	{
		/* recvfrom 如果没有数据就处于休眠状态 */
		iAddrLen = sizeof(struct sockaddr);
		iRecvLen = recvfrom(g_iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
		if (iRecvLen > 0)
		{
			ucRecvBuf[iRecvLen] = '\0';
			/* 解析数据:
			 * debuglevel=0, 1, 2, ... : 修改打印级别
			 * sdtout = 0                : 关闭stdout打印
			 * sdtout = 1                : 打开stdout打印
			 * netprint = 0              :关闭netprint打印
			 * netprint = 1              :打开netprint打印
			 * setclient                 : 设置接受打印信息的客户端
			 */
			if (strcmp((char *)ucRecvBuf, "setclient") == 0)
			{
				g_tSocketClientAddr = tSocketClientAddr;
				g_iHaveConnected    = 1;
			}
			else if (strncmp((char *)ucRecvBuf, "debuglevel=", 11) == 0)
			{
				SetDebugLevel((char *)ucRecvBuf);
			}
			else
			{
				SetDebugChannel((char *)ucRecvBuf);
			}
		}
	}

	return NULL;
}


static int NetDebugInit(void)
{
	int iRet;
	
	/* socket 初始化 */
	g_iSocketServer = socket(AF_INET, SOCK_DGRAM, 0); /* SOCK_DGRAM:UDP数据报 */
	if (g_iSocketServer == -1)
	{
		printf("socket error\n");
		return -1;
	}

	g_tSocketServerAddr.sin_family      = AF_INET;
	g_tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
	g_tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;          /* INADDR_ANY表示可以和任何的主机通信 */
	memset((unsigned char*)g_tSocketServerAddr.sin_zero, 0, sizeof(g_tSocketServerAddr.sin_zero));

	iRet = bind(g_iSocketServer, (const struct sockaddr *)&g_tSocketServerAddr, sizeof(struct sockaddr));
	if (iRet == -1)
	{
		printf("bind error\n");
		return -1;		
	}

	g_pcNetPrintBuf = (char *)malloc(PRINT_BUF_SIZE);
	if (g_pcNetPrintBuf == NULL)
	{
		close(g_iSocketServer);
		return -1;
	}
	
	/* 创建netprint发送线程:用来发送打印信息给客户端 */
	pthread_create(&g_tSendThreadID, NULL, NetDebugSendThreadFunction, NULL);
	
	/* 创建netprint接受线程:用来接受控制信息,比如修改打印级别、打开或关闭打印 */
 	pthread_create(&g_tRecvThreadID, NULL, NetDebugRecvThreadFunction, NULL);
	
	return 0;
}

static int NetDebugExit(void)
{
	/* 关闭socket,... */
	close(g_iSocketServer);
	free(g_pcNetPrintBuf);
	return 0;
}


static int NetDebugPrint(char *strData)
{
	/* 把数据放入环形缓冲区 */
	int i;
	for (i = 0; i < strlen(strData); i++)
	{
		if (0 != PutData(strData[i]))
			break;
	}

	/* 如果已经有客户端连接了,就把数据通过网络发送给客户端 */
	/* 可以使用sendto();或 唤醒线程(这里使用唤醒线程)唤醒netprint的发送线程 */ 
	pthread_mutex_lock(&g_tNetDebugSendMutex);
	pthread_cond_signal(&g_tNetDebugSendConVar);
	pthread_mutex_unlock(&g_tNetDebugSendMutex);
	
	return 0;
}


static T_DebugOpr g_tNetDebugOpr = {
	.name       = "netprint",
	.isCanUsed  = 1,
	.DebugInit  = NetDebugInit,
	.DebugExit  = NetDebugExit,
	.DebugPrint = NetDebugPrint,
};


int NetPrintInit(void)
{
	return RegisterDebugOpr(&g_tNetDebugOpr);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238

对于上述 netprint.c 的代码:

  • ① 对于 netprint.c,在网路通信中,我们把它作为服务端,所以初始化的时候,需要进行服务器相关的初始化操作;
  • ② 为了更快的打印速度,这里我们使用 UDP 的传输方式,避免 TCP 在传输出错时进行重传等操作导致打印速度慢的问题;
  • ③ 使用环形缓冲区存放需要发送的数据,如果有客户端连接了,就把数据通过网络发送给客户端 ;(关于环形缓冲区后面额外补充)
  • ④ 创建两个线程:发送线程、接收线程。其中,发送线程用于发送打印信息给客户端,接收线程用于接受控制信息,比如修改打印级别、打开或关闭打印;
  • ⑤ 创建后的发送线程和接收线程都处于休眠的状态,当接收线程接收到 “setclient” 表示已经连接上(实际上是获得了客户端的IP地址、端口等信息);连接上后,当有数据需要打印时,通过线程的条件变量唤醒发送线程,然后发送线程每次从环形缓冲区取出512字节的数据发送给客户端;
  • ⑥ 对于接收到的控制信息的处理, 需要在 debug_manager.c 添加如下函数:其中 SetDebugLevel 函数用于设置打印级别,SetDebugChannel 函数用于设置打印的渠道:打开/关闭标准输出,打开/关闭网络打印,DebugPrint 用于调用 T_DebugOpr 结构体的打印函数进行打印,InitDebugChannel 用于启动打印(初始化),前面的DebugInit只是注册T_DebugOpr结构体。
    #include <stdarg.h>
    
    static int g_iDebugLevelLimit = 8;
    
    /* strBuf = "debuglevel=<0~9>" */
    int SetDebugLevel(char *strBuf)
    {
    	g_iDebugLevelLimit = strBuf[11] - '0';
    	return 0;
    }
    
    /* sdtout = 0                : 关闭stdout打印
     * sdtout = 1                : 打开stdout打印
     * netprint = 0              :关闭netprint打印
     * netprint = 1              :打开netprint打印
     */
    int SetDebugChannel(char *strBuf)
    {
    	char *pStrTmp;
    	char strName[100];
    	PT_DebugOpr ptTmp;
    		
    	pStrTmp = strchr(strBuf, '=');
    	if (!pStrTmp)
    	{
    		return -1;
    	}
    	else
    	{
    		strncpy(strName, strBuf, (pStrTmp - strBuf));
    		strName[pStrTmp - strBuf] = '\0';
    		ptTmp = GetDebugOpr(strName);
    		if (!ptTmp)
    		{
    			return -1;
    		}
    
    		if (pStrTmp[1] == '0')
    		{
    			ptTmp->isCanUsed = 0;
    		}
    		else
    		{
    			ptTmp->isCanUsed = 1;
    		}
    		return 0;
    	}
    }
    
    /* 需要在debug_manager.c向外提供打印函数 */
    int DebugPrint(const char *pcFormat, ...)
    {
    	/* 调用链表中所有isCanUsed为1的结构体的       DebugPrint函数 */
    	char strTmpBuf[1000];
    	char *pcTmp;
    
    	va_list tArg;
    	int iNum;
    	PT_DebugOpr ptTmp = g_ptDebugOprHead;
    	int debuglevel = DEFAULT_DBGLEVEL;
    
    	va_start(tArg, pcFormat);
    	iNum = vsprintf(strTmpBuf, pcFormat, tArg);
    	va_end(tArg);
    
    	strTmpBuf[iNum] = '\0';
    
    	pcTmp = strTmpBuf;
    
    	/*根据打印级别决定是否打印 */
    	if ((strTmpBuf[0] == '<') && (strTmpBuf[2] == '>'))
    	{
    		debuglevel = strTmpBuf[1] - '0';
    
    		if (debuglevel >= 0 && debuglevel <= 9)
    		{
    			pcTmp = strTmpBuf + 3;
    		}
    		else
    		{
    			debuglevel = DEFAULT_DBGLEVEL;
    		}
    	}
    
    	if (debuglevel > g_iDebugLevelLimit)
    	{
    		return -1;
    	}
    	while (ptTmp)
    	{
    		if (ptTmp->isCanUsed)
    		{
    			ptTmp->DebugPrint(pcTmp);
    		}
    		ptTmp = ptTmp->ptNext;
    	}
    
    	return 0;
    }
    
    /* 启动打印,前面的DebugInit只是注册T_DebugOpr结构体 */
    int InitDebugChannel(void)
    {
    	PT_DebugOpr ptTmp = g_ptDebugOprHead;
    	while (ptTmp)
    	{
    		if (ptTmp->isCanUsed && ptTmp->DebugInit)
    		{
    			ptTmp->DebugInit();
    		}
    		ptTmp = ptTmp->ptNext;
    	}
    
    	return 0;	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115

额外补充: 环形缓冲区,其实我们可以理解为它是数组,如下图图所示:
在这里插入图片描述

  • ① 假设我们有一个长度为 10 的 buf,用于存放我们的数据,开始时读的位置 r 和写的位置 w 都是 0;
  • ② 写数据:buf[w] = val; 更新写的位置:w = (w + 1) % Len; (buf 的长度为 Len);
  • ③ 读数据:val = buf[r]; 更新读的位置:r = (r + 1) % Len;
  • ④ 判断环形缓冲区是否为空:r == w; 即当读的位置和写的位置相等时,环形缓冲区为空;
  • ⑤ 判断环形缓冲区是否已满:(w + 1) % Len == r; 即当写的下一个位置等于读的位置时,环形缓冲区已满;
  • ⑥ 环形缓冲区的代码如下:
    #define BUF_SIZE		(16*1024)	/* 环形缓冲区的最大空间为16K */
    
    static char g_cLoopBuf[BUF_SIZE];   /* 定义一个空间为16k的环形缓冲区 */
    
    /* 定义环形缓冲区的读写位置,初始值为0 */
    static int g_iReadPos  = 0;
    static int g_iWritePos = 0;
    
    /* 判断环形缓冲区是为空
    * 返回值:1:为空;0:不为空
    */
    static int isEmpty(void)
    {
    	return (g_iWritePos == g_iReadPos);
    }
    
    /* 判断环形缓冲区是否满
    * 返回值:1:满;0:不满
    */
    static int isFull(void)
    {
    	return (((g_iWritePos + 1) % BUF_SIZE) == g_iReadPos);
    }
    
    /* 往环形缓冲区存放一个数据
    * 返回值:0: 成功; -1:失败
    */
    static int PutData(char cVal)
    {
    	if (isFull())
    	{
    		return -1;
    	}
    	else
    	{
    		g_cLoopBuf[g_iWritePos] = cVal;
    		g_iWritePos = (g_iWritePos + 1) % BUF_SIZE;
    		return 0;
    	}
    }
    
    /* 从环形缓冲区读一个数据
    * 返回值:0: 成功; -1:失败
    */
    static int GetData(char *pcVal)
    {
    	if (isEmpty())
    	{
    		return -1;
    	}
    	else
    	{
    		*pcVal = g_cLoopBuf[g_iReadPos];
    		g_iReadPos = (g_iReadPos + 1) % BUF_SIZE;
    		return 0;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

4.把config.h的#define DBG_PRINTF printf 修改为 #define DBG_PRINTF DebugPrint

5.main.c的修改,在 main.c 中我们需要对 T_DebugOpr 结构体进行初始化,并启动 DebugPrint,同时添加响应的打印信息,main.c 的代码如下:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <config.h>
#include <draw.h>
#include <encoding_manager.h>
#include <fonts_manager.h>
#include <disp_manager.h>
#include <input_manager.h>
#include <debug_manager.h>
#include <string.h>

/* ./show_file [-s Size] [-d display] [-f font_file] [-h HZK] <text_file> */
int main(int argc, char **argv)
{
	int iError;
	unsigned int dwFontSize = 16;
	char acHzkFile[128];
	char acFreetypeFile[128];
	char acTextFile[128];
	char acDisplay[128];
	
	int bList = 0;

	T_InputEvent tInputEvent;
	
	acHzkFile[0]  = '\0';
	acFreetypeFile[0] = '\0';
	acTextFile[0] = '\0';
	strcpy(acDisplay, "fb");


	iError = DebugInit();
	if (iError)
	{
		DBG_PRINTF("DebugInit error!\n");
		return -1;
	}

	InitDebugChannel();

	while ((iError = getopt(argc, argv, "ls:f:h:d:")) != -1)
	{
		switch(iError)
		{
			case 'l':
			{
				bList = 1;
				break;
			}
			case 's':
			{
				  dwFontSize = strtoul(optarg, NULL, 0);
				  break;
			}
			case 'f':
			{
				  strncpy(acFreetypeFile, optarg, 128);
				  acFreetypeFile[127] = '\0';
				  break;
			}
			case 'h':
			{
					strncpy(acHzkFile, optarg, 128);
					acHzkFile[127] = '\0';
					break;
			}
			case 'd':
			{
				strncpy(acDisplay, optarg, 128);
				acDisplay[127] = '\0';
				break;
			}
			default:
			{
				  DBG_PRINTF("Usage: %s [-s Size] [-d display] [-f font_file] [-h HZK] <text_file>\n", argv[0]);
				  DBG_PRINTF("Usage: %s -l\n", argv[0]);
				  return -1;
				  break;
			}
		}
	}

	if (!bList && optind >= argc)
	{
		DBG_PRINTF("Usage: %s [-s Size] [-d display] [-f font_file] [-h HZK] <text_file>\n", argv[0]);
		DBG_PRINTF("Usage: %s -l\n", argv[0]);
		return -1;
	}

	iError = DisplayInit();
	if (iError)
	{
		DBG_PRINTF("DisplayInit error!\n");
		return -1;
	}

	iError = FontsInit();
	if (iError)
	{
		DBG_PRINTF("FontsInit error!\n");
		return -1;
	}

	iError = EncodingInit();
	if (iError)
	{
		DBG_PRINTF("EncodingInit error!\n");
		return -1;
	}

	iError = InputInit();
	if (iError)
	{
		DBG_PRINTF("InputInit error!\n");
		return -1;		
	}
	
	if (bList)
	{
		DBG_PRINTF("supported display:\n");
		ShowDispOpr();

		DBG_PRINTF("supported font:\n");
		ShowFontOpr();

		DBG_PRINTF("supported encoding:\n");
		ShowEncodingOpr();

		DBG_PRINTF("supported input:\n");
		ShowInputOpr();

		DBG_PRINTF("supported debug chanel:\n");
		ShowDebugOpr();
		
		return 0;
	}
	
	strncpy(acTextFile, argv[optind], 128);
	acTextFile[127] = '\0';
			
	iError = OpenTextFile(acTextFile);
	if (iError)
	{
		DBG_PRINTF("OpenTextFile error!\n");
		return -1;
	}

	iError = SetTextDetail(acHzkFile, acFreetypeFile, dwFontSize);
	if (iError)
	{
		DBG_PRINTF("SetTextDetail error!\n");
		return -1;
	}

	iError = SelectAndInitDisplay(acDisplay);
	if (iError)
	{
		DBG_PRINTF("SelectAndInitDisplay error!\n");
		return -1;
	}

	iError = AllInputDevicesInit();
	if (iError)
	{
		DBG_PRINTF("AllInputDevicesInit error!\n");
		return -1;
	}
	
	iError = ShowNextPage();
	if (iError)
	{
		DBG_PRINTF("Error to show first page\n");
		return -1;
	}

	DBG_PRINTF("Enter 'n' to show next page, 'u' to show previous page, 'q' to exit:\n");	
	while (1)
	{
		//printf("Enter 'n' to show next page, 'u' to show previous page, 'q' to exit: ");

		if (0 == GetInputEvent(&tInputEvent))
		{
			if (tInputEvent.iVal == INPUT_VALUE_DOWN)
			{
				ShowNextPage();
			}
			else if (tInputEvent.iVal == INPUT_VALUE_UP)
			{
				ShowPrePage();			
			}
			else if (tInputEvent.iVal == INPUT_VALUE_EXIT)
			{
				return 0;
			}
		}
	}
	return 0;	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199

6.客户端程序 netprint_client 的编写:改程序的主要功能是:① 接收服务器的打印信息,并通过 printf 从终端打印出来;② 向服务器发送控制信息。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>


/* socket
 * connect
 * send/recv
 */

#define SERVER_PORT 5678


/*
 * ./netprint_client <server_ip> debuglevel=<0-9>
 * ./netprint_client <server_ip> stdout=0|1
 * ./netprint_client <server_ip> netprint=0|1
 * ./netprint_client <server_ip> show // setclient,并且接收打印信息
 */

int main(int argc, char **argv)
{
	int iSocketClient;
	struct sockaddr_in tSocketServerAddr;
	
	int iRet;
	unsigned char ucRecvBuf[1000];
	int iSendLen;
	int iRecvLen;
	int iAddrLen;	
	
	if (argc != 3)
	{
		printf("Usage:\n");
		printf("%s <server_ip> debuglevel=<0-9>\n", argv[0]);
		printf("%s <server_ip> stdout=0|1\n", argv[0]);
		printf("%s <server_ip> netprint=0|1\n", argv[0]);
		printf("%s <server_ip> show\n", argv[0]);
		return -1;
	}	

	iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);
	tSocketServerAddr.sin_family      = AF_INET;
	tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
	if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
 	{
		printf("invalid server_ip\n");
		return -1;
	}
	memset(tSocketServerAddr.sin_zero, 0, 8);

	if (strcmp(argv[2], "show") == 0)
	{
		/* 发送数据 */
		iAddrLen = sizeof(struct sockaddr);
		iSendLen = sendto(iSocketClient, "setclient", 9, 0,
							  (const struct sockaddr *)&tSocketServerAddr, iAddrLen);

		while (1)
		{
			/* 循环: 从网络读数据, 打印出来 */
			iAddrLen = sizeof(struct sockaddr);
			iRecvLen = recvfrom(iSocketClient, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketServerAddr, &iAddrLen);
			if (iRecvLen > 0)
			{
				ucRecvBuf[iRecvLen] = '\0';
				printf("%s\n", ucRecvBuf);
			}
		}
	}
	else
	{
		/* 发送数据 */
		iAddrLen = sizeof(struct sockaddr);
		iSendLen = sendto(iSocketClient, argv[2], strlen(argv[2]), 0,
							  (const struct sockaddr *)&tSocketServerAddr, iAddrLen);
	}

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

7.测试:

  • ① 服务端 (即开发板):./show_file -s 24 -d fb -f MSYH.TTF -h HZK16 utf8.txt
  • ② 客户端:
    • ./netprint_client <server_ip> debuglevel=<0-9> 设置打印级别:1~9;
    • ./netprint_client <server_ip> stdout=0|1 关闭(0)、打开(1)标准输出;
    • /netprint_client <server_ip> netprint=0|1 关闭(0)、打开(1)网络打印;
    • /netprint_client <server_ip> show 打印接收到的信息。
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号