深度学习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 inputbuf[50];

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

char filename[20];

//用来存放文件名,如"/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[]中的下标值,

uipConnectTable[count]表示当前连接到哪个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_buf[54];

//在UDP中uip_sappdata = &uip_buf[42];

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_buf[54];在UDP中uip_sappdata = &uip_buf[42];

}

else

{

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

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

//在TCP中uip_sappdata = &uip_buf[54];在UDP中uip_sappdata = &uip_buf[42];

}

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_buf[54];

//在UDP中uip_sappdata = &uip_buf[42];

//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_buf[54];

//在UDP中uip_sappdata = &uip_buf[42];

//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_buf[54];

//如果紧急指针为0x0000,则在UDP中uip_sappdata = &uip_buf[42];

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_buf[54];

//如果紧急指针为0x0000,则在UDP中uip_sappdata = &uip_buf[42];

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_buf[54];

//如果紧急指针为0x0000,则在UDP中uip_sappdata = &uip_buf[42];

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__ */

/** @} */
相关推荐
wjs20248 小时前
并查集快速合并
开发语言
free-elcmacom8 小时前
MATLAB与高等数学<1>一道曲面积分题的几何直观
开发语言·数学建模·matlab·高等数学
Tony Bai8 小时前
Go 安全新提案:runtime/secret 能否终结密钥残留的噩梦?
java·开发语言·jvm·安全·golang
pengzhuofan8 小时前
Java演进与与工程师成长
java·开发语言
比昨天多敲两行8 小时前
C++入门基础
开发语言·c++
月明长歌8 小时前
再谈Java 继承与多态:从“能用”到“精通”,更深一层的原理与设计思维
java·开发语言
hoiii1878 小时前
量子密钥分发密钥率仿真MATLAB实现
开发语言·matlab
hefaxiang9 小时前
分支循环(下)(二)
c语言·开发语言·数据结构
小武~9 小时前
Leetcode 每日一题C 语言版 -- 45 jump game ii
c语言·算法·leetcode