• 以前printf信息从串口上打印出来
    • 麻烦、不好管理、速率慢
  • 引入网络编程,将打印信息通过网络传输到某台机器上观察
  • 数据传输三要素:源、目的、长度
  • image.png
  • 怎么写程序?
  • 文件读写image.png
  • 服务器image.png
  • send发数据、recv接收数据
  • image.png

Domain,是域的意思 ,分别在数学,计算机学和生物学里有不同的解释和应用。

UDP

  • image.png
  • UDP中connect函数并没有实际建立连接链路(UDP也不需要建立链路),只是形式上的获取了目的信息;可以不使用connect函数、利用sendto函数发送数据效果是一样的

网络字节顺序采用big-endian(大端)排序方式;很多嵌入式设备都是采用小端字节序的,需要转换(保险起见,无论设备是大端还是小端,都进行字节序转换,实现与设备无关) unsigned long int htonl(unsigned long int hostlong) unsigned short int htons(unisgned short int hostshort) unsigned long int ntohl(unsigned long int netlong) unsigned short int ntohs(unsigned short int netshort) 在这四个转换函数中,h 代表host, n 代表 network.s 代表short l 代表long

有点小问题

  • 客户端中指定连接的是服务器的地址和端口
  • 服务端绑定特定端口和地址(一般设为任意地址)
  • 客户端的地址信息什么时候填充发送给服务器了? connect中应该填充了
  • 机器中的回环地址和实际网卡地址都可以使用

修改电子书源码支持远程打印

  • 增加debug目录image.png
  • image.png
  • 可变参数 ```c

    include

    include

int StdoutDebugPrint(const char pccFormat, …) { / 直接把输出信息用printf打印出来即可 */ va_list tArgs; int iNum;

  1. va_start(tArgs, pccFormat);
  2. iNum = vfprintf(stdout, pccFormat, tArgs);
  3. va_end(tArgs);
  4. return iNum;

}

  1. - 看看glibc库中printf的实现
  2. - 所有的库函数都可以在glibc中找到其实现方式
  3. netprint
  4. - NetDbgInit(), NetDbgExit(), NetDbgPrint()
  5. ```c
  6. #define PRINT_BUF_SIZE 16*1024
  7. static char * g_pcNetPrintBuf;
  8. static char * g_pcBufTmp;
  9. static int NetDbgInit(void)
  10. {
  11. /* 初始化socket */
  12. ...
  13. /* 分配g_pcNetPrintBuf */
  14. g_pcNetPrintBuf = malloc(1024*16);
  15. g_pcBufTmp = malloc(1024);
  16. }
  17. static int NetDbgExit(void)
  18. {
  19. /* 退出socket */
  20. /* 释放内存 */
  21. free(g_pcNetPrintBuf);
  22. free(g_pcBufTmp);
  23. }
  24. /* 将临时缓冲区的数据写入g_pcNetPrintBuf */
  25. static int PutData(char cVal)
  26. {
  27. if(!isFull()){
  28. g_pcNetPrintBuf[g_iWritePos] = cVal;
  29. g_iWritePos = (g_iWritePos+1) % PRINT_BUF_SIZE;
  30. return 0;
  31. }else
  32. return -1;
  33. }
  34. /* 取数据 */
  35. static int GetData(char *pcVal)
  36. {
  37. if(!isEmpty()){
  38. *pcVal = g_pcNetPrintBuf[g_iReadPos];
  39. g_iReadPos = (g_iReadPos+1) % PRINT_BUF_SIZE;
  40. return 0;
  41. }
  42. }
  43. static int NetDbgPrint(const char *pccFormat, ...)
  44. {
  45. /* 把数据放入缓冲区 */
  46. /* 环形缓冲区 */
  47. va_list tArgs;
  48. int iNum;
  49. va_start(tArgs, pccFormat);
  50. iNum = vsfprintf(g_pcBufTmp, pccFormat, tArgs); /* 先把数据打印到临时缓冲区中 */
  51. va_end(tArgs);
  52. for(i=0; i<iNUm; i++){
  53. if(0 != PutData(g_pcBufTmp[i]))
  54. break;
  55. }
  56. /* 如果由客户端连接了,就通过网络把数据发送给客户端 */
  57. /* 可以使用sendto() 或 唤醒线程 */
  58. pthread_mutex_lock(&g_tNetDbgSendMutex);
  59. pthread_cond_signal(&g_tNetDbgSendConVar);
  60. pthread_mutex_unlock(&g_tNetDbgSendMutex);
  61. }

pthread_cond_wait 条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程使”条件成立”(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

  • 设置打印级别

仿照内核image.png

/* 根据打印级别决定是否打印 */
    if ((strTmpBuf[0] == '<') && (strTmpBuf[2] == '>'))
    {
        dbglevel = strTmpBuf[1] - '0';
        if (dbglevel >= 0 && dbglevel <= 9)
        {
            pcTmp = strTmpBuf + 3;
        }
        else
        {
            dbglevel = DEFAULT_DBGLEVEL;
        }
    }
  • 函数定义在使用之前的话,可以不用进行声明
  • static类型的函数不应该在头文件中进行声明

telnet服务

  • telnetd -l /bin/sh 启动telnet服务
  • Telnet协议是TCP/IP协议族中的一员,是Internet远程登录服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力