正确的 send & recv 行为

本文介绍了在实现socket类时的一些最佳实践,包括如何处理阻塞与非阻塞模式的切换,发送接收数据的操作流程,以及如何应对常见的错误情况如EWOULDBLOCK、ENOBUF等。

在实现socket类时,

1) 最好把设置block, nonblock等函数作为内部接口, 不向外开放

2) 当指定发送/接受时间时, 正确/典型的编码过程是:

 

  a) 确保设置为nonblock模式

  b) 异步发送;当未发送完全是循环发送;当发送出错(EWOULDBLOCK, ENOBUF)时, select注册FD_WRITE事件, select返回时判断返回值确定是否可发送或者已经出错或者超时

  c) 发送结束时, 恢复nonblock之前的状态

 

 

接受也是如此操作。

 

 

对于另外两种错误, 似乎也需要做如上处理: EINTR, EAGAIN

 

3) socket只向外提供发送接受操作的接口

 

------------------------------------------done-----------------------------------------------------------

#include <REGX52.H> typedef unsigned char u8; typedef unsigned int u16; typedef unsigned long int u32; // 引脚定义 sbit buzzer = P0^0; // 蜂鸣器 sbit relay1 = P3^0; // 继电器1 sbit relay2 = P3^1; // 继电器2 sbit SEG = P0^1; // 数码管段码控制引脚 sbit DIG = P2^0; // 数码管位码控制引脚 // 数码管段码表(0-9,灭屏码) u8 gsmg_code[11] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x00}; u32 display_num = 0; // 待显示数值(初始为学号后4位,取最后一位) u8 key_value = 0; // 按键值 u8 recv_buf[20] = {0}; // 串口接收缓冲区 u8 recv_len = 0; // 接收数据长度 u8 recv_complete = 0; // 接收完成标志 u8 student_id = 4; // 学号后4位的最后一位(示例,需替换为实际值) u8 buzzer_flag = 0; // 蜂鸣器工作标志 u16 buzzer_time = 0; // 蜂鸣器持续时间 u16 buzzer_counter = 0; // 蜂鸣器PWM计数器 // 函数声明 void delay(u16 time); u8 anjian_scan(void); void smg_display(u8 num); void configuart(u16 baud); void configtimer0(void); void process_command(void); void send_string(u8 *str); void main() { // 初始化 EA = 1; // 开启总中断 configuart(9600); // 初始化串口 configtimer0(); // 初始化定时器0 display_num = student_id % 10; // 初始显示学号后4位的最后一位(示例) while (1) { smg_display(display_num % 10); // 显示个位数 key_value = anjian_scan(); // 扫描按键 // 处理按键输入 if (key_value != 0) { u8 send_buf[10]; sprintf(send_buf, "K%d ON\r\n", key_value); send_string(send_buf); key_value = 0; } // 处理接收完成的命令 if (recv_complete) { process_command(); recv_complete = 0; recv_len = 0; } } } // 延时函数 void delay(u16 time) { while (time--); } // 矩阵按键扫描 u8 anjian_scan(void) { static u8 keyvalue = 0; P1 = 0x0f; if (P1 != 0x0f) { delay(1000); if (P1 != 0x0f) { P1 = 0x0f; switch (P1) { case 0x07: keyvalue = 1; break; case 0x0b: keyvalue = 2; break; case 0x0d: keyvalue = 3; break; case 0x0e: keyvalue = 4; break; } P1 = 0xf0; switch (P1) { case 0x70: keyvalue = keyvalue; break; case 0xb0: keyvalue = keyvalue + 4; break; case 0xd0: keyvalue = keyvalue + 8; break; case 0xe0: keyvalue = keyvalue + 12; break; } while (P1 != 0xf0); } } else { keyvalue = 0; } return keyvalue; } // 数码管显示(静态显示) void smg_display(u8 num) { DIG = 1; // 位码使能(选中数码管) SEG = 0; // 先消影 delay(1); SEG = gsmg_code[num]; // 输出段码 delay(100); SEG = 0; // 消影 DIG = 0; // 关闭位码 } // 串口初始化 void configuart(u16 baud) { SCON = 0x50; // 串口模式1,允许接收 TMOD &= 0x0F; TMOD |= 0X20; // 定时器T1模式2 TH1 = 256 - (11059200 / 12 / 32 / baud); // 计算波特率初值 TL1 = TH1; ET1 = 0; // 关闭T1中断 TR1 = 1; // 启动T1 ES = 1; // 开启串口中断 } // 定时器0初始化(用于PWM驱动无源蜂鸣器) void configtimer0(void) { TMOD &= 0xF0; TMOD |= 0x01; // 定时器0模式1(16位) TH0 = 0xFF; // 初值决定PWM频率(可调整) TL0 = 0x00; ET0 = 1; // 开启定时器0中断 TR0 = 0; // 初始不启动 } // 串口中断函数 void interruptUART() interrupt 4 { if (RI == 1) { RI = 0; if (recv_len < 19) { recv_buf[recv_len++] = SBUF; // 检测回车换行结束符 if (recv_len >= 2 && recv_buf[recv_len-2] == '\r' && recv_buf[recv_len-1] == '\n') { recv_complete = 1; } } } if (TI == 1) { TI = 0; } } // 定时器0中断函数(PWM生成) void timer0_isr() interrupt 1 { buzzer_counter++; if (buzzer_flag) { buzzer = ~buzzer; // 翻转电平,生成方波 // 到达设定时间后停止蜂鸣器 if (buzzer_counter >= buzzer_time) { buzzer_flag = 0; TR0 = 0; // 停止定时器 buzzer = 0; // 关闭蜂鸣器 } } // 重新加载初值 TH0 = 0xFF; TL0 = 0x00; } // 发送字符串 void send_string(u8 *str) { while (*str) { SBUF = *str++; while (!TI); TI = 0; } } // 处理命令 void process_command() { u8 *ptr; u16 value; // 处理蜂鸣器命令:AT+beep:xxx if (recv_buf[0] == 'A' && recv_buf[1] == 'T' && recv_buf[2] == '+' && recv_buf[3] == 'b' && recv_buf[4] == 'e' && recv_buf[5] == 'e' && recv_buf[6] == 'p' && recv_buf[7] == ':') { ptr = recv_buf + 8; value = 0; while (*ptr >= '0' && *ptr <= '9') { value = value * 10 + (*ptr - '0'); ptr++; } if (value <= 65535) { buzzer_flag = 1; buzzer_time = value; buzzer_counter = 0; TR0 = 1; // 启动定时器生成PWM } } // 处理数码管显示命令:AT+led:xxxx else if (recv_buf[0] == 'A' && recv_buf[1] == 'T' && recv_buf[2] == '+' && recv_buf[3] == 'l' && recv_buf[4] == 'e' && recv_buf[5] == 'd' && recv_buf[6] == ':') { ptr = recv_buf + 7; display_num = 0; while (*ptr >= '0' && *ptr <= '9') { display_num = display_num * 10 + (*ptr - '0'); ptr++; } if (display_num > 0xFFFF) display_num = 0xFFFF; // 限制最大值65535 } // 处理继电器1命令:AT+relay1:xxx else if (recv_buf[0] == 'A' && recv_buf[1] == 'T' && recv_buf[2] == '+' && recv_buf[3] == 'r' && recv_buf[4] == 'e' && recv_buf[5] == 'l' && recv_buf[6] == 'a' && recv_buf[7] == 'y' && recv_buf[8] == '1' && recv_buf[9] == ':') { ptr = recv_buf + 10; value = 0; while (*ptr >= '0' && *ptr <= '9') { value = value * 10 + (*ptr - '0'); ptr++; } if (value <= 65535) { relay1 = 1; delay(value); relay1 = 0; } } // 处理继电器2命令:AT+relay2:xxxx else if (recv_buf[0] == 'A' && recv_buf[1] == 'T' && recv_buf[2] == '+' && recv_buf[3] == 'r' && recv_buf[4] == 'e' && recv_buf[5] == 'l' && recv_buf[6] == 'a' && recv_buf[7] == 'y' && recv_buf[8] == '2' && recv_buf[9] == ':') { ptr = recv_buf + 10; value = 0; while (*ptr >= '0' && *ptr <= '9') { value = value * 10 + (*ptr - '0'); ptr++; } if (value <= 65535) { relay2 = 1; delay(value); relay2 = 0; } } } }分析这个代码存在的问题
06-20
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值