18,356
社区成员
发帖
与我相关
我的任务
分享
/*------------------------------------------------------------------------------------*/
// BUF 是定义为了TCPIP的头格式的结构体
void
lzm_tcpchksum(void)
{
u16_t hsum=0, sum=0;
BUF->len[0] = (((uip_len-0x000e)) >> 8);
BUF->len[1] = (((uip_len-0x000e)) & 0xff);
BUF->tcpchksum = 0;
BUF->ipchksum = 0;
lzm_ipchksum();
hsum=lzm_tcp_psh_chksum();
if((sum += hsum) < hsum) {
++sum;
}
hsum=lzm_tcp_hd_chksum();
if((sum += hsum) < hsum) {
++sum;
}
hsum=lzm_tcp_data_chksum();
if((sum += hsum) < hsum) {
++sum;
}
BUF->tcpchksum = ~sum;
}
if(uip_appdata[0]=='C') //假如收到的数据 第一个是‘C’就将这串数据返回去
{
uip_send(&uip_appdata[0],uip_len);
}
这个是在上层的,如果我后面没有做其他动作是绝对可行的,而且没哟问题,执行了上面这个函数后,实际上要发送数据的话是转到网卡驱动进行发送数据的:dev_send()
void dev_send(void)
{ if(uip_appdata[1]=='1')
{
// uip_len = uip_len+1;
// uip_buf[uip_len-1]='9';
lzm_tcpchksum();
}
enc28j60Packet_len(uip_len);
enc28j60Packet_data(uip_len, uip_buf);
enc28j60Packet_Send();
}
上面的代码表示,我在PC机TCP客户端向TCP服务器发送数据,第一个数据是'C'(这样才能够进入发送数据函数),第二个数据是 '1'那么就进行校验和计算 lzm_tcpchksum()(这里我重新计算 IP头校验和、TCP头校验和(TCP伪头部、TCP Head、还有数据));
1.如果if里面的那两个注释掉的语句没有执行,那么这个代码执行过程没有出错,不会卡住的。
2.但是假如我把那两个注释掉的语句去掉注释,执行代码后,就只能发送一次了。
3.如果我把那两句注释掉的代码
// uip_len = uip_len+1;
// uip_buf[uip_len-1]='9';
改成 uip_appdata[1]='8';//就吧这个数据随便改一个,来验证我的校验和程序代码是否可行
那么这个代码执行过程没有出错,不会卡住的。
详细问题我只能描述这样了,不知道大家看懂了没有哦。那这个和TCP的 顺序号 填充有关系么?求指教啦~~~[/quote]
lzm_tcpchksum这个的代码能贴上来吗?我是用单片机控制ENC28J60来实现单片机和PC机间通过网络进行通信,现在,由于单片机的RAM不大吧,而有时候需要发送一串叫大的数据比如说900字节的,那单片机只能分多次写入 网卡驱动,然后再一次性发送出去了。所以必须在网卡驱动层进行动手了,所以在发送长长的数据前,必须先构造 IP TCP的头 那些校验和什么的,然后将数据 多次写入网卡发送缓冲区,最后再一次发送,只有这样才可以实现啊。要不我也不想弄的这么麻烦了额。 楼主你又不玩RawSocket,研究那么多干啥呢?
楼主你又不玩RawSocket,研究那么多干啥呢?
u16_t
lzm_ipchksum(void)
{
BUF->ipchksum = ~(uip_chksum((u16_t *)&uip_buf[UIP_LLH_LEN], 20));//IP从 14 字节开始,长度是20
return 1;
}
/*-----------------------------------------------------------------------------------*/
u16_t
lzm_tcp_psh_chksum(void)//这是TCP伪首部 校验和
{
u16_t hsum=0, sum=0;
if((sum += BUF->srcipaddr[0]) < BUF->srcipaddr[0]) {
++sum;
}
if((sum += BUF->srcipaddr[1]) < BUF->srcipaddr[1]) {
++sum;
}
if((sum += BUF->destipaddr[0]) < BUF->destipaddr[0]) {
++sum;
}
if((sum += BUF->destipaddr[1]) < BUF->destipaddr[1]) {
++sum;
}
if((sum += (u16_t)htons((u16_t)IP_PROTO_TCP)) < (u16_t)htons((u16_t)IP_PROTO_TCP)) {
++sum;
}
hsum = (u16_t)htons((((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - 20);
if((sum += hsum) < hsum) {
++sum;
}
return sum;
}
/*------------------------------------------------------------------------------------*/
u16_t
lzm_tcp_hd_chksum(void)//这是TCP头部
{
u16_t sum=0;
sum = uip_chksum((u16_t *)&uip_buf[20 + UIP_LLH_LEN], 20);//TCP 头 的数据从 14+20 位置开始,长度是20
return sum;
}
/*------------------------------------------------------------------------------------*/
u16_t
lzm_tcp_data_chksum(void)
{
u16_t sum=0;
/* Compute the checksum of the data in the TCP packet */
sum = uip_chksum((u16_t *)uip_appdata,
(u16_t)(((((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - 40)));//数据的长度其实是 uip_len-14-20-20了
return sum;
}
/*------------------------------------------------------------------------------------*/
uip_buf如果是以太网包,你怎么能够简单在以太网包后面加个‘9’呢? uip_buf如果是IP包,那uip_len怎么在函数lzm_tcpchksum里又变成以太网包的长度?
struct arp_hdr {
struct uip_eth_hdr ethhdr;
u16_t hwtype;
u16_t protocol;
u8_t hwlen;
u8_t protolen;
u16_t opcode;
struct uip_eth_addr shwaddr;
u16_t sipaddr[2];
struct uip_eth_addr dhwaddr;
u16_t dipaddr[2];
};
struct uip_eth_hdr {
struct uip_eth_addr dest;
struct uip_eth_addr src;
u16_t type;
};
typedef struct {
/* IP header. */
u8_t vhl,
tos,
len[2],
ipid[2],
ipoffset[2],
ttl,
proto;
u16_t ipchksum;
u16_t srcipaddr[2],
destipaddr[2];
/* TCP header. */
u16_t srcport,
destport;
u8_t seqno[4],
ackno[4],
tcpoffset,
flags,
wnd[2];
u16_t tcpchksum;
u8_t urgp[2];
u8_t optdata[4];
} uip_tcpip_hdr;
这前面的 14 字节应该是uip0.9程序中自己有处理的,在发送的时候自己添加以太网帧头的,这个uip_buf应该是 以太网帧头(14B)+IP头(20B)+TCP头(20B)+数据; 这个数据在程序中就定义为了:
uip_appdata = &uip_buf[40 + UIP_LLH_LEN];//UIP_LLH_LEN = 14
这个不知道说明白了没有,要不我源代码弄上来吧,http://pan.baidu.com/share/link?shareid=2327368036&uk=604832080或许是我对这个 uip0.9 理解的不够,因为代码里面涉及到的都是TCP/IP协议这类的东西,我还不是很熟。真是麻烦您啦。
void dev_send(void)
{ if(uip_appdata[1]=='1')
{
// uip_len = uip_len+1;
// uip_buf[uip_len-1]='9';
lzm_tcpchksum();
}
enc28j60Packet_len(uip_len);
enc28j60Packet_data(uip_len, uip_buf);
enc28j60Packet_Send();
}
这里的uip_buf是代表IP包还是以太网包BUF->len[0] = (((uip_len-0x000e)) >> 8); BUF->len[1] = (((uip_len-0x000e)) & 0xff); 这里为什么要减去14呢?
[quote=引用 8 楼 kaly_liu 的回复:] [quote=引用 7 楼 huwji_stanley_apple 的回复:] [quote=引用 3 楼 tiger9991 的回复:] 你自定义的协议,每个通信帧竟然没有长度? 一般都有长度控制字节,这样才能帮助达到不粘包之类的功能啊。不然你怎么知道这帧数据有多长呢?这和变长不变长没关系的。 CRC怎么计算都有直接的函数的。就是验证是否通信帧是否由于通信问题导致错误。解释原理也很简单的。