深度学习uip中的“psock.c和psock.h”

深度学习uip中的psock.c和psock.h,由于"psock.c和psock.h"在源文件中,结构定义很分散,这里我做了修改,另外把pt协程进行替换。

#define My_REPLACEMENT 0 //PT协程不用替换

#define My_REPLACEMENT 1 //PT协程替换

替换后的代码,可以仿真,跟踪,便于理解pt协程的工作原理。本文对uIP协议栈中的psock.c和psock.h文件进行了深度解析和重构。通过条件编译保留原始实现和修改后的实现,便于对比分析。新增了更详细的代码注释,解释了TCP/UDP缓冲区位置等关键细节。该重构提高了代码可读性和可调试性,为理解uIP协议栈的protothread实现机制提供了清晰参考。

1、uip中的psock.h

#ifndef PSOCK_H

#define PSOCK_H

#include "uipopt.h"

#include "pt.h"

//pt协程的状态"struct psock结构"中的state的值定义

#define STATE_NONE 0 //pt协程的初始状态

#define STATE_ACKED 1 //收到TCP应答

#define STATE_READ 2 //"读完新数据标志"

#define STATE_BLOCKED_NEWDATA 3

//如果发现"读完新数据标志"建立,则进入阻塞读新数据

#define STATE_BLOCKED_CLOSE 4 //程序没有使用

#define STATE_BLOCKED_SEND 5 //程序没有使用

#define STATE_DATA_SENT 6 //有新数据等待发送

struct psock_buf {

u8_t *ptr; //输入缓冲区的剩余空间的首地址

unsigned short left; //输入缓冲区的剩余字节数

};

struct psock {

struct pt pt; //协程状态变量pt.lc

struct pt psockpt; //协程状态变量psockpt.lc

/* Protothreads - one that's using the psock functions, and one that runs inside the psock functions. */

const u8_t *sendptr;

/*待发送数据的下一组数据的指针,Pointer to the next data to be sent. */

u8_t *readptr;

/*待读取的下一组数据的指针,Pointer to the next data to be read. */

char *bufptr;

/*传入数据的缓冲区的指针,Pointer to the buffer used for buffering incoming data. */

u16_t sendlen;

/*待发送数据的剩余字节数,The number of bytes left to be sent. */

u16_t readlen;

/*待读取的剩余字节数,The number of bytes left to be read. */

struct psock_buf buf;

/*输入缓冲区的状态,The structure holding the state of the input buffer. */

unsigned int bufsize;

/*输入缓冲区的大小,The size of the input buffer. */

unsigned char state;

/*pt协程的状态,The state of the protosocket. */

};

struct httpd_fs_file {

char *data; //指向发送"网页数据"的首地址

int len; //发送"网页数据"的长度

};

struct httpd_state {

unsigned char timer;

//若"轮询标志"建立,则"中止连接标志"计时器开始工作

struct psock sin; //用来管理http输入数据

struct psock sout; //用来管理http输出数据

struct pt outputpt; //协程状态变量outputpt.lc

struct pt scriptpt; //协程状态变量scriptpt.lc,用来处理script

char inputbuf50;

//用来保存接收到的"WEB指令GET","/r"或"/ "

char filename20;

//用来存放文件名,如"/index.html","/404.html","/favicon.ico"

char state;

//指示HTTP数据的输出状态:0为STATE_WAITING,1为STATE_OUTPUT

struct httpd_fs_file file; //网页数据的首地址和数据长度

int len;

/*若待发送数据长度大于最大段,则按照最大段的长度发送,

否则按照实际长度发送;

*/

char *scriptptr; //脚本指针script

int scriptlen; //脚本指针script指向的数据长度

unsigned short count;

/*为TCP连接表uipConnectTable\[\]中的下标值,

uipConnectTablecount表示当前连接到哪个IP地址和端口*/

};

void psock_init(struct psock *psock, char *buffer, unsigned int buffersize);

//初始化一个协程,Initialize a protosocket.

#define PSOCK_INIT(psock, buffer, buffersize) psock_init(psock, buffer, buffersize)

#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt))

//在一个函数中启动原套接字原线程。

//Start the protosocket protothread in a function.

PT_THREAD(psock_send(struct psock *psock, const char *buf, unsigned int len));

//Send data.

//将buf\[\]中前len个字节拷贝到首地址为uip_sappdata的发送缓冲区,待发送数据的长度为uip_slen=len

#define PSOCK_SEND(psock, data, datalen) PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, data, datalen))

#define PSOCK_SEND_STR(psock, str) PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, str, strlen(str)))

//str指向待发送字符串的首地址,strlen(str)为str指向待发送字符串的长度

//将str\[\]中中的字符串拷贝到首地址为uip_sappdata的发送缓冲区

//待发送数据的长度为uip_slen,即字符串长度

PT_THREAD(psock_generator_send(struct psock *s,unsigned short (*f)(void *), void *arg));

//将s->file.data为首地址的前s->len个字节拷贝到uip_sappdata为首地址的"发送缓存"

//使用函数生成数据并发送数据,Generate data with a function and send it

#define PSOCK_GENERATOR_SEND(psock, generator, arg) PT_WAIT_THREAD(&((psock)->pt),psock_generator_send(psock, generator, arg))

#define PSOCK_CLOSE(psock) uip_close()

//关闭一个协程,Close a protosocket.

PT_THREAD(psock_readbuf(struct psock *s));

//读取数据,直到缓冲区已满。Read data until the buffer is full.

#define PSOCK_READBUF(s) PT_WAIT_THREAD(&((s)->pt), psock_readbuf(s))

PT_THREAD(psock_readto(struct psock *s, unsigned char c));

//读取数据到指定的字符,即c的值。Read data up to a specified character.

#define PSOCK_READTO(s, c) PT_WAIT_THREAD( &((s)->pt), psock_readto(s, c) )

u16_t psock_datalen(struct psock *psock);

#define PSOCK_DATALEN(psock) psock_datalen(psock)

//之前读取的数据的长度。

//The length of the data that was previously read.

#define PSOCK_EXIT(psock) PT_EXIT(&((psock)->pt))

//退出一个协程的协线程。 Exit the protosocket's protothread.

//关闭一个协程,并退出该协程的协线程。

//Close a protosocket and exit the protosocket's protothread.

#define PSOCK_CLOSE_EXIT(psock) \

do { \

PSOCK_CLOSE(psock); \

PSOCK_EXIT(psock); \

} while(0)

//声明原套接字的原线程的结束。

//Declare the end of a protosocket's protothread.

#define PSOCK_END(psock) PT_END(&((psock)->pt))

char psock_newdata(struct psock *s);

//检查新数据是否已到达原套接字上。

//Check if new data has arrived on a protosocket.

#define PSOCK_NEWDATA(psock) psock_newdata(psock)

//返回1,在uip_appdata为首地址的缓冲区中有新数据等待读取

//返回0,在uip_appdata为首地址的缓冲区中的所有数据已经读取

#define PSOCK_WAIT_UNTIL(psock, condition) PT_WAIT_UNTIL(&((psock)->pt), (condition));

//Wait until a condition is true.

#define PSOCK_WAIT_THREAD(psock, condition) PT_WAIT_THREAD(&((psock)->pt), (condition))

#endif /* PSOCK_H */

2、uip中的psock.c

#include "psock.h"

#include "string.h" //使能strcpy(),strlen(),memset(),NULL

#include "stdio.h" //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "uip.h"

#include "uip-conf.h"

#define BUF_NOT_FOUND 0

#define BUF_NOT_FULL 0

#define BUF_FULL 1

#define BUF_FOUND 2

//函数功能:

//设置buf->ptr = bufptr;它是"输入缓冲区"的剩余空间的首地址

//设置buf->left.left = bufsize;它是"输入缓冲区"的剩余字节数

static void buf_setup(struct psock_buf *buf, u8_t *bufptr, u16_t bufsize)

{

buf->ptr = bufptr;

//buf->ptr为"输入缓冲区"的剩余空间的首地址

buf->left = bufsize;

//buf->left为"输入缓冲区"的剩余字节数

//令buf->ptr = bufptr;buf->left.left = bufsize;

}

//函数功能:

//(*sourceDataPointer)指向uip_buf\[\]中的某个存储单元;

//(*sourceDataLength)为uip_buf\[\]中的剩余字节数;

//返回BUF_NOT_FULL,表示目的buf\[\]未装满,但源数据被读完了;

//返回BUF_FULL,表示目的buf\[\]装满,源数据可能没有被读完

static u8_t buf_bufdata(struct psock_buf *buf, u16_t len, u8_t **sourceDataPointer, u16_t *sourceDataLength)

{

if(*sourceDataLength < buf->left)

//buf\[\]的剩余空间可以装下(*sourceDataLength)个字节,还有剩余

{

memcpy(buf->ptr, *sourceDataPointer, *sourceDataLength);

buf->ptr += *sourceDataLength; // 修改buf\[\]的剩余空间的首地址

buf->left -= *sourceDataLength; // 修改buf\[\]的剩余空间的字节数

*sourceDataPointer += *sourceDataLength;//修改源数据指针

*sourceDataLength = 0;

//buf\[\]可以装下(*sourceDataLength)个字节,所以设置(*sourceDataLength)=0

return BUF_NOT_FULL;//返回0,表示buf\[\]未满

}

else if(*sourceDataLength == buf->left)

//buf\[\]的剩余空间刚好可以装下(*sourceDataLength)个字节,没有剩余

{

memcpy(buf->ptr, *sourceDataPointer, *sourceDataLength);

buf->ptr += *sourceDataLength;//装完数据后,buf\[\]的剩余空间的首地址

buf->left = 0;

//buf\[\]的剩余空间刚好可以装下(*sourceDataLength)个字节,所以没有剩余

*sourceDataPointer += *sourceDataLength;//装完数据后,修改源数据指针

*sourceDataLength = 0;

//buf\[\]可以装下(*sourceDataLength)个字节,所以设置(*sourceDataLength)=0

return BUF_FULL;//返回1,表示buf\[\]满

}

else//buf\[\]的剩余空间一次性装不下(*sourceDataLength)个字节

{

memcpy(buf->ptr, *sourceDataPointer, buf->left);

buf->ptr += buf->left;//装完数据后,buf\[\]的剩余空间的首地址

*sourceDataLength -= buf->left;//装完数据后,计算源数据的剩余字节数

*sourceDataPointer += buf->left;//装完数据后,修改源数据指针

buf->left = 0;

//buf\[\]装不下(*sourceDataLength)个字节,所以buf\[\]的剩余空间的字节数为0

return BUF_FULL;//返回1,表示buf\[\]满

}

}

//函数功能:若读到"endmarker的值",则返回BUF_FOUND或(BUF_FOUND | BUF_FULL)

//*buf是输入缓冲区的剩余空间的首地址

//endmarker的值是要读的目标数据

//*sourceDataPointer为"待读取的下一组数据的指针",指向uip_buf\[\]中的某个存储单元;

//*sourceDataLength为待读取的剩余字节数,为uip_buf\[\]中的剩余字节数;

//返回BUF_NOT_FOUND,表示没有找到"结束符号endmarker",buf\[\]可能未满

//返回BUF_FULL,表示没有找到"结束符号endmarker",但是目的缓存buf\[\]满了

//返回BUF_FOUND,表示找到"结束符号endmarker",buf\[\]可能未满

//返回BUF_FOUND | BUF_FULL,表示找到"结束符号endmarker",但是目的缓存buf\[\]满了;

static u8_t buf_bufto(register struct psock_buf *buf, u8_t endmarker,register u8_t **sourceDataPointer, register u16_t *sourceDataLength)

{

u8_t c;

while(buf->left > 0 && *sourceDataLength > 0)

{

c = **sourceDataPointer;

*buf->ptr = c;//buf->ptr为"输入缓冲区的剩余空间的首地址"

++*sourceDataPointer;//源数据的指针加1

++buf->ptr; //buf\[\]的剩余空间首地址加1

--*sourceDataLength; //源数据的剩余长度减1

--buf->left; //buf\[\]的剩余空间的字节数减1

if(c == endmarker)//找到"结束符号endmarker"

{

return BUF_FOUND;//返回2,表示找到"结束符号",buf\[\]可能未满

}

}

if(*sourceDataLength == 0)//继续找"结束符号endmarker",发现源数据被找完了

{

return BUF_NOT_FOUND;//返回0,表示没有找到"结束符号endmarker"

}

while(*sourceDataLength > 0)//继续找"结束符号endmarker",说明目的缓存buf\[\]满了

{

c = **sourceDataPointer;

--*sourceDataLength; //源数据的剩余长度减1

++*sourceDataPointer; //源数据的指针加1

if(c == endmarker)//找到"结束符号endmarker"

{

return BUF_FOUND | BUF_FULL;

//返回3,表示找到"结束符号endmarker",但是目的缓存buf\[\]满了

}

}

//执行到此处,说明目的缓存buf\[\]满了

return BUF_FULL;//返回1,表示没有找到"结束符号endmarker",但是目的缓存buf\[\]满了

}

//将s->sendptr\[\]中前uip_slen个字节拷贝到首地址为uip_sappdata的发送缓冲区,待发送数据的长度为uip_slen,返回值为1

//返回值为0,无发送数据

//在TCP中uip_sappdata = &uip_buf54;

//在UDP中uip_sappdata = &uip_buf42;

static char send_data(register struct psock *s)

{

u8_t tmpFlags;

u16_t sizeMAX;

tmpFlags=uip_rexmit();

//令tmpFlags=uip_flags & UIP_REXMIT,查询是否要"重新传输上次发送的数据"

if(s->state != STATE_DATA_SENT || tmpFlags)

{

sizeMAX=uip_mss();//读"最大段"的大小

if(s->sendlen > sizeMAX)

{

uip_send(s->sendptr, sizeMAX);

/*将s->sendptr\[\]中前sizeMAX个字节拷贝到首地址为uip_sappdata的发送缓冲区,待发送数据的长度为uip_slen*/

//在TCP中uip_sappdata = &uip_buf54;在UDP中uip_sappdata = &uip_buf42;

}

else

{

uip_send(s->sendptr, s->sendlen);

/*将s->sendptr\[\]中前s->sendlen个字节拷贝到首地址为uip_sappdata的发送缓冲区,待发送数据的长度为uip_slen*/

//在TCP中uip_sappdata = &uip_buf54;在UDP中uip_sappdata = &uip_buf42;

}

s->state = STATE_DATA_SENT; //修改"pt协程的状态为"发送状态"STATE_DATA_SENT

return 1;

}

return 0;

}

//接收到的TCP应答标志后,需要"修改剩余长度s->sendlen,剩余空间的首地址s->sendptr",返回值为1

static char data_acked(register struct psock *s)

{

u16_t sizeMAX;

u8_t tmpFlags;

tmpFlags=uip_acked();

//令tmpFlags=(uip_flags & UIP_ACKDATA),读接收到的TCP应答标志

if(s->state == STATE_DATA_SENT && tmpFlags)

{

sizeMAX=uip_mss();//读"最大段"的大小

if(s->sendlen > sizeMAX)//一次性发送不完

{

s->sendlen -= sizeMAX;// 收到的TCP应答标志后,修改剩余字节数

s->sendptr += sizeMAX;// 收到的TCP应答标志后,修改发送缓存的首地址

}

else//一次性发完

{

s->sendptr += s->sendlen;// 收到的TCP应答标志后,修改发送缓存的首地址

s->sendlen = 0;// 收到的TCP应答标志后,修改剩余字节数

}

s->state = STATE_ACKED; //修改"pt协程的状态为"收到的TCP应答标志"STATE_ACKED

return 1;

}

return 0;//没收到的TCP应答标志,或者没有进入发送状态

}

//将buf\[\]中前len个字节拷贝到首地址为uip_sappdata的发送缓冲区,待发送数据的长度为uip_slen=len

//在TCP中uip_sappdata = &uip_buf54;

//在UDP中uip_sappdata = &uip_buf42;

//buf指向待发送数据的首地址

//len为待发送数据的长度

PT_THREAD(psock_send(register struct psock *s, const char *buf,unsigned int len))

{

#if My_REPLACEMENT==0

PT_BEGIN(&s->psockpt);

if(len == 0)//待发送数据长度为0,退出

{

PT_EXIT(&s->psockpt);

}

//保存指向要发送的数据的长度和指针。

s->sendptr = (const u8_t*)buf;

s->sendlen = len;

s->state = STATE_NONE;

while(s->sendlen > 0)

{

PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));

/*send_data(s)将s->sendptr\[\]中前uip_slen个字节拷贝到首地址为uip_sappdata的发送缓冲区,待发送数据的长度为uip_slen,返回值为1;data_acked(s)接收到的TCP应答标志后,需要"修改剩余长度s->sendlen,剩余空间的首地址s->sendptr",返回值为1*/

}

s->state = STATE_NONE;

PT_END(&s->psockpt);

#else

{PT_YIELD_FLAG = 1;switch(s->psockpt.lc){case 0:

if(len == 0)

{

s->psockpt.lc=0;return PT_EXITED;

}

s->sendptr = (const u8_t*)buf; //保存指向要发送的数据的指针。

s->sendlen = len; //保存指向要发送的数据的长度。

s->state = STATE_NONE;

while(s->sendlen > 0)

{//"__LINE__宏"在源文件中出现的行号

s->psockpt.lc=LINE;case LINE:if( !( data_acked(s) & send_data(s) ) ){return PT_WAITING;}

/*send_data(s)将s->sendptr\[\]中前uip_slen个字节拷贝到首地址为uip_sappdata的发送缓冲区,待发送数据的长度为uip_slen,返回值为1;data_acked(s)接收到的TCP应答标志后,需要"修改剩余长度s->sendlen,剩余空间的首地址s->sendptr",返回值为1*/

}

s->state = STATE_NONE;

}PT_YIELD_FLAG = 0;s->psockpt.lc=0;return PT_ENDED;}

#endif

}

//将s->file.data为首地址的前s->len个字节拷贝到uip_sappdata为首地址的"发送缓存"

//在TCP中uip_sappdata = &uip_buf54;

//在UDP中uip_sappdata = &uip_buf42;

//generate=generate_part_of_file()

PT_THREAD(psock_generator_send(register struct psock *s,unsigned short (*generate)(void *), void *arg))

{

#if My_REPLACEMENT==0

PT_BEGIN(&s->psockpt);

/* Ensure that there is a generator function to call. */

if(generate == NULL) {

PT_EXIT(&s->psockpt);

}

/* Call the generator function to generate the data in the uip_appdata buffer. */

s->sendlen = generate(arg);//装载发送数据的长度

s->sendptr = uip_appdata; //装载发送数据的首地址

s->state = STATE_NONE;

do {

/* Call the generator function again if we are called to perform a retransmission. */

if(uip_rexmit())

{

generate(arg);

}

/* Wait until all data is sent and acknowledged. */

PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));

/*send_data(s)将s->sendptr\[\]中前uip_slen个字节拷贝到首地址为uip_sappdata的发送缓冲区,待发送数据的长度为uip_slen,返回值为1;data_acked(s)接收到的TCP应答标志后,需要"修改剩余长度s->sendlen,剩余空间的首地址s->sendptr",返回值为1*/

} while(s->sendlen > 0);

s->state = STATE_NONE;

PT_END(&s->psockpt);

#else

{PT_YIELD_FLAG = 1;switch(s->psockpt.lc){case 0:

if(generate == NULL)

{

s->psockpt.lc=0;return PT_EXITED;

}

s->sendlen = generate(arg);//装载发送数据的长度

s->sendptr = uip_appdata; //装载发送数据的首地址

s->state = STATE_NONE;

do

{

if(uip_rexmit()){generate(arg);}

s->psockpt.lc = LINE;case LINE:if( !(data_acked(s) & send_data(s)) )return PT_WAITING;

/*send_data(s)将s->sendptr\[\]中前uip_slen个字节拷贝到首地址为uip_sappdata的发送缓冲区,待发送数据的长度为uip_slen,返回值为1;data_acked(s)接收到的TCP应答标志后,需要"修改剩余长度s->sendlen,剩余空间的首地址s->sendptr",返回值为1*/

} while(s->sendlen > 0);

s->state = STATE_NONE;

}s->psockpt.lc=0;PT_YIELD_FLAG = 0;return PT_ENDED;}

#endif

}

//之前读取的数据的长度。The length of the data that was previously read.

u16_t psock_datalen(struct psock *psock)

{

return psock->bufsize - psock->buf.left;

//psock->bufsize为"输入缓冲区的大小"

//psock->buf.left是"输入缓冲区的剩余字节数"

//计算psock->bufsize\[\]读到的字节数量

}

//函数功能:

//返回1,有新数据等待读取;返回0,没有新数据等待读取;

char psock_newdata(struct psock *s)

{

if(s->readlen > 0)//"待读取的剩余字节数"大于0

{

return 1;

}

else if(s->state == STATE_READ)//发现"读完新数据标志"建立

{

s->state = STATE_BLOCKED_NEWDATA;

//修改"pt协程的状态"为新数据读完STATE_BLOCKED_NEWDATA

return 0;//没有新数据

}

else if(uip_newdata())//发现"建立收到新数据标志"

{

return 1;

}

else

{

/*没有新数据 There is no new data. */

return 0;

}

}

//读取数据到指定的字符c,即c的值。

PT_THREAD(psock_readto(register struct psock *s, unsigned char c))

{

u8_t ret;

#if My_REPLACEMENT==0

PT_BEGIN(&s->psockpt);

buf_setup(&s->buf, (u8_t*)s->bufptr, s->bufsize);

//令s->buf.ptr = s->bufptr;s->buf.left.left = s->bufsize;

/* XXX: Should add buf_checkmarker() before do{} loop, if

incoming data has been handled while waiting for a write. */

do

{

if(s->readlen == 0)//剩余字节数为0

{

PT_WAIT_UNTIL(&s->psockpt, psock_newdata(s));

//psock_newdata()返回1,有新数据等待读取;psock_newdata()返回0,没有新数据等待读取;

s->state = STATE_READ;//修改"pt协程的状态"为建立"读完新数据标志"

s->readptr = (u8_t *)uip_appdata;

//s->readptr为"待读取的下一组数据的指针"

//如果紧急指针为0x0000,则在TCP中uip_sappdata = &uip_buf54;

//如果紧急指针为0x0000,则在UDP中uip_sappdata = &uip_buf42;

s->readlen = uip_datalen();//令s->readlen=uip_len

}

ret=buf_bufto(&s->buf, c,&s->readptr, &s->readlen);

//s->buf是输入缓冲区的剩余空间的首地址

//c的值是要读的目标数据

//s->readptr为"待读取的下一组数据的指针"

//s->readlen为待读取的剩余字节数

//返回BUF_NOT_FOUND,表示没有找到c,s->buf\[\]可能未满

//返回BUF_FULL,表示没有找到c,但是目的缓存s->buf\[\]满了

//返回BUF_FOUND,表示找到c,s->buf\[\]可能未满

//返回BUF_FOUND | BUF_FULL,表示找到c,但是目的缓存s->buf\[\]满了;

ret=(u8_t)(ret & BUF_FOUND);

} while( ret == 0 );

if(psock_datalen(s) == 0)//之前读取的数据的长度。

{

s->state = STATE_NONE;//修改"pt协程的状态"为"pt协程的初始状态"

PT_RESTART(&s->psockpt);

}

PT_END(&s->psockpt);

#else

{PT_YIELD_FLAG = 1;switch(s->psockpt.lc){case 0:

buf_setup(&s->buf, (u8_t*)s->bufptr, s->bufsize);

//设置s->buf.ptr = s->bufptr;它是输入缓冲区的剩余空间的首地址

//s->bufptr为传入数据的缓冲区的指针

//设置s->buf.left = s->bufsize;它是输入缓冲区的剩余字节数

//s->bufsize为输入缓冲区的大小

do

{

if(s->readlen == 0)//待读取的剩余字节数为0

{

s->psockpt.lc = LINE; case LINE:if( !( psock_newdata(s) ) )return PT_WAITING;

//psock_newdata()返回1,有新数据等待读取;psock_newdata()返回0,没有新数据等待读取;

//如果"有新数据等待读取",则执行下面的语句

s->state = STATE_READ; //修改"pt协程的状态"为建立"读完新数据标志"

s->readptr = (u8_t *)uip_appdata;

//s->readptr为"待读取的下一组数据的指针"

//如果紧急指针为0x0000,则在TCP中uip_sappdata = &uip_buf54;

//如果紧急指针为0x0000,则在UDP中uip_sappdata = &uip_buf42;

s->readlen = uip_datalen();

//令s->readlen=uip_len,s->readlen为待读取的剩余字节数

}

ret=buf_bufto(&s->buf, c,&s->readptr, &s->readlen);

//s->buf是输入缓冲区的剩余空间的首地址

//c的值是要读的目标数据,若读到"c的值",则返回BUF_FOUND或(BUF_FOUND | BUF_FULL)

//s->readptr为"待读取的下一组数据的指针"

//s->readlen为待读取的剩余字节数

//ret=BUF_NOT_FOUND,表示没有找到c,s->buf\[\]可能未满

//ret=BUF_FULL,表示没有找到c,但是目的缓存s->buf\[\]满了

//ret=BUF_FOUND,表示找到c,s->buf\[\]可能未满

//ret=BUF_FOUND | BUF_FULL,表示找到c,但是目的缓存s->buf\[\]满了;

ret=(u8_t)(ret & BUF_FOUND);

} while( ret == 0 );

if(psock_datalen(s) == 0)//如果"之前读取的数据的长度"为0

{

s->state = STATE_NONE; //修改"pt协程的状态"为"pt协程的初始状态"

s->psockpt.lc=0;return PT_WAITING;

}

}PT_YIELD_FLAG = 0;s->psockpt.lc=0;return PT_ENDED;}

#endif

}

//读取数据,直到缓冲区已满。

PT_THREAD(psock_readbuf(register struct psock *s))

{

u8_t ret;

#if My_REPLACEMENT==0

PT_BEGIN(&s->psockpt);

buf_setup(&s->buf, (u8_t*)s->bufptr, s->bufsize);

//令s->buf.ptr = s->bufptr;s->buf.left.left = s->bufsize;

/* XXX: Should add buf_checkmarker() before do{} loop, if

incoming data has been handled while waiting for a write. */

do {

if(s->readlen == 0)

{

PT_WAIT_UNTIL(&s->psockpt, psock_newdata(s));

//psock_newdata()返回1,有新数据等待读取;psock_newdata()返回0,没有新数据等待读取;

s->state = STATE_READ; //修改"pt协程的状态"为建立"读完新数据标志"

s->readptr = (u8_t *)uip_appdata;

//s->readptr为"待读取的下一组数据的指针",指向uip_buf\[\]中的某个存储单元

s->readlen = uip_datalen();//令s->readlen=uip_len,为uip_buf\[\]中的剩余字节数

}

ret=buf_bufdata(&s->buf, s->bufsize,&s->readptr,&s->readlen);

//ret=BUF_NOT_FULL,表示s->buf\[\]未满,但源数据被装完了;

//ret=BUF_FULL,表示s->buf\[\]满,源数据可能没有被装完

} while( ret != BUF_FULL );

if(psock_datalen(s) == 0) {

s->state = STATE_NONE; //修改"pt协程的状态"为"pt协程的初始状态"

PT_RESTART(&s->psockpt);

}

PT_END(&s->psockpt);

#else

{PT_YIELD_FLAG = 1;switch(s->psockpt.lc) { case 0:

buf_setup(&s->buf, (u8_t*)s->bufptr, s->bufsize);

//令s->buf.ptr = s->bufptr;s->buf.left.left = s->bufsize;

do {

if(s->readlen == 0)

{

s->psockpt.lc = LINE; case LINE:if( !( psock_newdata(s) ) )return PT_WAITING;

//psock_newdata()返回1,有新数据等待读取;psock_newdata()返回0,没有新数据等待读取;

//如果"有新数据等待读取",则执行下面的语句

s->state = STATE_READ; //修改"pt协程的状态"为建立"读完新数据标志"

s->readptr = (u8_t *)uip_appdata;

//s->readptr为"待读取的下一组数据的指针",指向uip_buf\[\]中的某个存储单元

//如果紧急指针为0x0000,则在TCP中uip_sappdata = &uip_buf54;

//如果紧急指针为0x0000,则在UDP中uip_sappdata = &uip_buf42;

s->readlen = uip_datalen();//令s->readlen=uip_len,为uip_buf\[\]中的剩余字节数

}

ret=buf_bufdata(&s->buf, s->bufsize,&s->readptr,&s->readlen);

//ret=BUF_NOT_FULL,表示s->buf\[\]未满,但源数据被装完了;

//ret=BUF_FULL,表示s->buf\[\]满,源数据可能没有被装完

} while( ret != BUF_FULL );

//源数据被装完了

if(psock_datalen(s) == 0)//如果"之前读取的数据的长度"为0

{

s->state = STATE_NONE; //修改"pt协程的状态"为"pt协程的初始状态"

s->psockpt.lc=0;return PT_WAITING;

}

}PT_YIELD_FLAG = 0;s->psockpt.lc=0;return PT_ENDED;}

#endif

}

void psock_init(register struct psock *psock, char *buffer, unsigned int buffersize)

{

psock->state = STATE_NONE; //修改"pt协程的状态"为"pt协程的初始状态"

psock->readlen = 0; //待读取的剩余字节数

psock->bufptr = buffer; //传入数据的缓冲区的指针

psock->bufsize = buffersize;//psock->bufsize为"输入缓冲区的大小"

buf_setup(&psock->buf, (u8_t*)buffer, buffersize);

//设置buf->ptr = buffer;它是输入缓冲区的剩余空间的首地址

//设置buf->left.left = buffersize;它是输入缓冲区的剩余字节数

#if My_REPLACEMENT==0

PT_INIT(&psock->pt);

PT_INIT(&psock->psockpt);

#else

psock->pt.lc=0;

psock->psockpt.lc=0;

#endif

}

3、附上uip中psock.c的源文件:

复制代码
#include "stdio.h"
#include "string.h"

#include "uipopt.h"
#include "psock.h"
#include "uip.h"

#define STATE_NONE 0
#define STATE_ACKED 1
#define STATE_READ 2
#define STATE_BLOCKED_NEWDATA 3
#define STATE_BLOCKED_CLOSE 4
#define STATE_BLOCKED_SEND 5
#define STATE_DATA_SENT 6


#define BUF_NOT_FULL 0
#define BUF_NOT_FOUND 0


#define BUF_FULL 1


#define BUF_FOUND 2

/*---------------------------------------------------------------------------*/
static void
buf_setup(struct psock_buf *buf,
	  u8_t *bufptr, u16_t bufsize)
{
  buf->ptr = bufptr;
  buf->left = bufsize;
}
/*---------------------------------------------------------------------------*/
static u8_t
buf_bufdata(struct psock_buf *buf, u16_t len,
	    u8_t **dataptr, u16_t *datalen)
{
  if(*datalen < buf->left) {
    memcpy(buf->ptr, *dataptr, *datalen);
    buf->ptr += *datalen;
    buf->left -= *datalen;
    *dataptr += *datalen;
    *datalen = 0;
    return BUF_NOT_FULL;
  } else if(*datalen == buf->left) {
    memcpy(buf->ptr, *dataptr, *datalen);
    buf->ptr += *datalen;
    buf->left = 0;
    *dataptr += *datalen;
    *datalen = 0;
    return BUF_FULL;
  } else {
    memcpy(buf->ptr, *dataptr, buf->left);
    buf->ptr += buf->left;
    *datalen -= buf->left;
    *dataptr += buf->left;
    buf->left = 0;
    return BUF_FULL;
  }
}
/*---------------------------------------------------------------------------*/
static u8_t
buf_bufto(register struct psock_buf *buf, u8_t endmarker,
	  register u8_t **dataptr, register u16_t *datalen)
{
  u8_t c;
  while(buf->left > 0 && *datalen > 0) {
    c = *buf->ptr = **dataptr;
    ++*dataptr;
    ++buf->ptr;
    --*datalen;
    --buf->left;
    
    if(c == endmarker) {
      return BUF_FOUND;
    }
  }

  if(*datalen == 0) {
    return BUF_NOT_FOUND;
  }

  while(*datalen > 0) {
    c = **dataptr;
    --*datalen;
    ++*dataptr;
    
    if(c == endmarker) {
      return BUF_FOUND | BUF_FULL;
    }
  }
  
  return BUF_FULL;
}
/*---------------------------------------------------------------------------*/
static char
send_data(register struct psock *s)
{
  if(s->state != STATE_DATA_SENT || uip_rexmit()) {
    if(s->sendlen > uip_mss()) {
      uip_send(s->sendptr, uip_mss());
    } else {
      uip_send(s->sendptr, s->sendlen);
    }
    s->state = STATE_DATA_SENT;
    return 1;
  }
  return 0;
}
/*---------------------------------------------------------------------------*/
static char
data_acked(register struct psock *s)
{
  if(s->state == STATE_DATA_SENT && uip_acked()) {
    if(s->sendlen > uip_mss()) {
      s->sendlen -= uip_mss();
      s->sendptr += uip_mss();
    } else {
      s->sendptr += s->sendlen;
      s->sendlen = 0;
    }
    s->state = STATE_ACKED;
    return 1;
  }
  return 0;
}
/*---------------------------------------------------------------------------*/
PT_THREAD(psock_send(register struct psock *s, const char *buf,unsigned int len))
{
  PT_BEGIN(&s->psockpt);

  /* If there is no data to send, we exit immediately. */
  if(len == 0) {
    PT_EXIT(&s->psockpt);
  }

  /* Save the length of and a pointer to the data that is to be
     sent. */
  s->sendptr = (const u8_t*)buf;
  s->sendlen = len;

  s->state = STATE_NONE;

  /* We loop here until all data is sent. The s->sendlen variable is
     updated by the data_sent() function. */
  while(s->sendlen > 0) {

    /*
     * The condition for this PT_WAIT_UNTIL is a little tricky: the
     * protothread will wait here until all data has been acknowledged
     * (data_acked() returns true) and until all data has been sent
     * (send_data() returns true). The two functions data_acked() and
     * send_data() must be called in succession to ensure that all
     * data is sent. Therefore the & operator is used instead of the
     * && operator, which would cause only the data_acked() function
     * to be called when it returns false.
     */
    PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
  }

  s->state = STATE_NONE;
  
  PT_END(&s->psockpt);
}
/*---------------------------------------------------------------------------*/
PT_THREAD(psock_generator_send(register struct psock *s,unsigned short (*generate)(void *), void *arg))
{
  PT_BEGIN(&s->psockpt);

  /* Ensure that there is a generator function to call. */
  if(generate == NULL) {
    PT_EXIT(&s->psockpt);
  }

  /* Call the generator function to generate the data in the
     uip_appdata buffer. */
  s->sendlen = generate(arg);
  s->sendptr = uip_appdata;

  s->state = STATE_NONE;  
  do {
    /* Call the generator function again if we are called to perform a
       retransmission. */
    if(uip_rexmit()) {
      generate(arg);
    }
    /* Wait until all data is sent and acknowledged. */
    PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
  } while(s->sendlen > 0);
  
  s->state = STATE_NONE;
  
  PT_END(&s->psockpt);
}
/*---------------------------------------------------------------------------*/
u16_t
psock_datalen(struct psock *psock)
{
  return psock->bufsize - psock->buf.left;
}
/*---------------------------------------------------------------------------*/
char
psock_newdata(struct psock *s)
{
  if(s->readlen > 0) {
    /* There is data in the uip_appdata buffer that has not yet been
       read with the PSOCK_READ functions. */
    return 1;
  } else if(s->state == STATE_READ) {
    /* All data in uip_appdata buffer already consumed. */
    s->state = STATE_BLOCKED_NEWDATA;
    return 0;
  } else if(uip_newdata()) {
    /* There is new data that has not been consumed. */
    return 1;
  } else {
    /* There is no new data. */
    return 0;
  }
}
/*---------------------------------------------------------------------------*/
PT_THREAD(psock_readto(register struct psock *psock, unsigned char c))
{
  PT_BEGIN(&psock->psockpt);

  buf_setup(&psock->buf, (u8_t*)psock->bufptr, psock->bufsize);
  
  /* XXX: Should add buf_checkmarker() before do{} loop, if
     incoming data has been handled while waiting for a write. */

  do {
    if(psock->readlen == 0) {
      PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
      psock->state = STATE_READ;
      psock->readptr = (u8_t *)uip_appdata;
      psock->readlen = uip_datalen();
    }
  } while((buf_bufto(&psock->buf, c,
		     &psock->readptr,
		     &psock->readlen) & BUF_FOUND) == 0);
  
  if(psock_datalen(psock) == 0) {
    psock->state = STATE_NONE;
    PT_RESTART(&psock->psockpt);
  }
  PT_END(&psock->psockpt);
}
/*---------------------------------------------------------------------------*/
PT_THREAD(psock_readbuf(register struct psock *psock))
{
  PT_BEGIN(&psock->psockpt);

  buf_setup(&psock->buf, (u8_t*)psock->bufptr, psock->bufsize);
  
  /* XXX: Should add buf_checkmarker() before do{} loop, if
     incoming data has been handled while waiting for a write. */

  do {
    if(psock->readlen == 0) {
      PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
      printf("Waited for newdata\n");
      psock->state = STATE_READ;
      psock->readptr = (u8_t *)uip_appdata;
      psock->readlen = uip_datalen();
    }
  } while(buf_bufdata(&psock->buf, psock->bufsize,
			 &psock->readptr,
			 &psock->readlen) != BUF_FULL);

  if(psock_datalen(psock) == 0) {
    psock->state = STATE_NONE;
    PT_RESTART(&psock->psockpt);
  }
  PT_END(&psock->psockpt);
}
/*---------------------------------------------------------------------------*/
void
psock_init(register struct psock *psock, char *buffer, unsigned int buffersize)
{
  psock->state = STATE_NONE;
  psock->readlen = 0;
  psock->bufptr = buffer;
  psock->bufsize = buffersize;
  buf_setup(&psock->buf, (u8_t*)buffer, buffersize);
  PT_INIT(&psock->pt);
  PT_INIT(&psock->psockpt);
}
/*---------------------------------------------------------------------------*/

4、附上uip中psock.h的源文件:

复制代码
#ifndef __PSOCK_H__
#define __PSOCK_H__

#include "uipopt.h"
#include "pt.h"

 /*
 * The structure that holds the state of a buffer.
 *
 * This structure holds the state of a uIP buffer. The structure has
 * no user-visible elements, but is used through the functions
 * provided by the library.
 *
 */
struct psock_buf {
  u8_t *ptr;
  unsigned short left;
};

/**
 * The representation of a protosocket.
 *
 * The protosocket structrure is an opaque structure with no user-visible
 * elements.
 */
struct psock {
  struct pt pt, psockpt; /* Protothreads - one that's using the psock
			    functions, and one that runs inside the
			    psock functions. */
  const u8_t *sendptr;   /* Pointer to the next data to be sent. */
  u8_t *readptr;         /* Pointer to the next data to be read. */
  
  char *bufptr;          /* Pointer to the buffer used for buffering
			    incoming data. */
  
  u16_t sendlen;         /* The number of bytes left to be sent. */
  u16_t readlen;         /* The number of bytes left to be read. */

  struct psock_buf buf;  /* The structure holding the state of the
			    input buffer. */
  unsigned int bufsize;  /* The size of the input buffer. */
  
  unsigned char state;   /* The state of the protosocket. */
};

void psock_init(struct psock *psock, char *buffer, unsigned int buffersize);
/**
 * Initialize a protosocket.
 *
 * This macro initializes a protosocket and must be called before the
 * protosocket is used. The initialization also specifies the input buffer
 * for the protosocket.
 *
 * \param psock (struct psock *) A pointer to the protosocket to be
 * initialized
 *
 * \param buffer (char *) A pointer to the input buffer for the
 * protosocket.
 *
 * \param buffersize (unsigned int) The size of the input buffer.
 *
 * \hideinitializer
 */
#define PSOCK_INIT(psock, buffer, buffersize) \
  psock_init(psock, buffer, buffersize)

/**
 * Start the protosocket protothread in a function.
 *
 * This macro starts the protothread associated with the protosocket and
 * must come before other protosocket calls in the function it is used.
 *
 * \param psock (struct psock *) A pointer to the protosocket to be
 * started.
 *
 * \hideinitializer
 */
#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt))

PT_THREAD(psock_send(struct psock *psock, const char *buf, unsigned int len));
/**
 * Send data.
 *
 * This macro sends data over a protosocket. The protosocket protothread blocks
 * until all data has been sent and is known to have been received by
 * the remote end of the TCP connection.
 *
 * \param psock (struct psock *) A pointer to the protosocket over which
 * data is to be sent.
 *
 * \param data (char *) A pointer to the data that is to be sent.
 *
 * \param datalen (unsigned int) The length of the data that is to be
 * sent.
 *
 * \hideinitializer
 */
#define PSOCK_SEND(psock, data, datalen)		\
    PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, data, datalen))

/**
 * \brief      Send a null-terminated string.
 * \param psock Pointer to the protosocket.
 * \param str  The string to be sent.
 *
 *             This function sends a null-terminated string over the
 *             protosocket.
 *
 * \hideinitializer
 */
#define PSOCK_SEND_STR(psock, str)      		\
    PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, str, strlen(str)))

PT_THREAD(psock_generator_send(struct psock *psock,
				unsigned short (*f)(void *), void *arg));

/**
 * \brief      Generate data with a function and send it
 * \param psock Pointer to the protosocket.
 * \param generator Pointer to the generator function
 * \param arg   Argument to the generator function
 *
 *             This function generates data and sends it over the
 *             protosocket. This can be used to dynamically generate
 *             data for a transmission, instead of generating the data
 *             in a buffer beforehand. This function reduces the need for
 *             buffer memory. The generator function is implemented by
 *             the application, and a pointer to the function is given
 *             as an argument with the call to PSOCK_GENERATOR_SEND().
 *
 *             The generator function should place the generated data
 *             directly in the uip_appdata buffer, and return the
 *             length of the generated data. The generator function is
 *             called by the protosocket layer when the data first is
 *             sent, and once for every retransmission that is needed.
 *
 * \hideinitializer
 */
#define PSOCK_GENERATOR_SEND(psock, generator, arg)     \
    PT_WAIT_THREAD(&((psock)->pt),					\
		   psock_generator_send(psock, generator, arg))


/**
 * Close a protosocket.
 *
 * This macro closes a protosocket and can only be called from within the
 * protothread in which the protosocket lives.
 *
 * \param psock (struct psock *) A pointer to the protosocket that is to
 * be closed.
 *
 * \hideinitializer
 */
#define PSOCK_CLOSE(psock) uip_close()

PT_THREAD(psock_readbuf(struct psock *psock));
/**
 * Read data until the buffer is full.
 *
 * This macro will block waiting for data and read the data into the
 * input buffer specified with the call to PSOCK_INIT(). Data is read
 * until the buffer is full..
 *
 * \param psock (struct psock *) A pointer to the protosocket from which
 * data should be read.
 *
 * \hideinitializer
 */
#define PSOCK_READBUF(psock)				\
  PT_WAIT_THREAD(&((psock)->pt), psock_readbuf(psock))

PT_THREAD(psock_readto(struct psock *psock, unsigned char c));
/**
 * Read data up to a specified character.
 *
 * This macro will block waiting for data and read the data into the
 * input buffer specified with the call to PSOCK_INIT(). Data is only
 * read until the specifieed character appears in the data stream.
 *
 * \param psock (struct psock *) A pointer to the protosocket from which
 * data should be read.
 *
 * \param c (char) The character at which to stop reading.
 *
 * \hideinitializer
 */
#define PSOCK_READTO(psock, c)				\
  PT_WAIT_THREAD(&((psock)->pt), psock_readto(psock, c))

/**
 * The length of the data that was previously read.
 *
 * This macro returns the length of the data that was previously read
 * using PSOCK_READTO() or PSOCK_READ().
 *
 * \param psock (struct psock *) A pointer to the protosocket holding the data.
 *
 * \hideinitializer
 */
#define PSOCK_DATALEN(psock) psock_datalen(psock)

u16_t psock_datalen(struct psock *psock);

/**
 * Exit the protosocket's protothread.
 *
 * This macro terminates the protothread of the protosocket and should
 * almost always be used in conjunction with PSOCK_CLOSE().
 *
 * \sa PSOCK_CLOSE_EXIT()
 *
 * \param psock (struct psock *) A pointer to the protosocket.
 *
 * \hideinitializer
 */
#define PSOCK_EXIT(psock) PT_EXIT(&((psock)->pt))

/**
 * Close a protosocket and exit the protosocket's protothread.
 *
 * This macro closes a protosocket and exits the protosocket's protothread.
 *
 * \param psock (struct psock *) A pointer to the protosocket.
 *
 * \hideinitializer
 */
#define PSOCK_CLOSE_EXIT(psock)		\
  do {						\
    PSOCK_CLOSE(psock);			\
    PSOCK_EXIT(psock);			\
  } while(0)

/**
 * Declare the end of a protosocket's protothread.
 *
 * This macro is used for declaring that the protosocket's protothread
 * ends. It must always be used together with a matching PSOCK_BEGIN()
 * macro.
 *
 * \param psock (struct psock *) A pointer to the protosocket.
 *
 * \hideinitializer
 */
#define PSOCK_END(psock) PT_END(&((psock)->pt))

char psock_newdata(struct psock *s);

/**
 * Check if new data has arrived on a protosocket.
 *
 * This macro is used in conjunction with the PSOCK_WAIT_UNTIL()
 * macro to check if data has arrived on a protosocket.
 *
 * \param psock (struct psock *) A pointer to the protosocket.
 *
 * \hideinitializer
 */
#define PSOCK_NEWDATA(psock) psock_newdata(psock)

/**
 * Wait until a condition is true.
 *
 * This macro blocks the protothread until the specified condition is
 * true. The macro PSOCK_NEWDATA() can be used to check if new data
 * arrives when the protosocket is waiting.
 *
 * Typically, this macro is used as follows:
 *
 \code
 PT_THREAD(thread(struct psock *s, struct timer *t))
 {
   PSOCK_BEGIN(s);

   PSOCK_WAIT_UNTIL(s, PSOCK_NEWADATA(s) || timer_expired(t));
   
   if(PSOCK_NEWDATA(s)) {
     PSOCK_READTO(s, '\n');
   } else {
     handle_timed_out(s);
   }
   
   PSOCK_END(s);
 }
 \endcode
 *
 * \param psock (struct psock *) A pointer to the protosocket.
 * \param condition The condition to wait for.
 *
 * \hideinitializer
 */
#define PSOCK_WAIT_UNTIL(psock, condition)    \
  PT_WAIT_UNTIL(&((psock)->pt), (condition));

#define PSOCK_WAIT_THREAD(psock, condition)   \
  PT_WAIT_THREAD(&((psock)->pt), (condition))

#endif /* __PSOCK_H__ */

/** @} */
相关推荐
Scott9999HH2 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社3 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海3 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖4 小时前
JDK 26 新特性详解
java·开发语言
马优晨5 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区7 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大7 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai7 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜8 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa8 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio