在C++程序中添加逻辑流程控制(上)

上一篇 / 下一篇  2007-01-24 15:35:00 / 个人分类:听说

问题的引出

  在计算机程序中,除了常见的执行流程控制,还有逻辑流程控制;有时,执行流程即为逻辑流程,但在大多数情况下还是有所区别的,例如,假定有一个Web服务器使用同步套接字读取HTTP请求,那么会编写如下的代码:

void read(HTTP_REQUEST& http_request)
{
read(http_request.header);
read(http_request.body, http_request.header);
}

void read(HTTP_REQUEST_HEADER& header)
{
string line = read_line();
parse_request_link(line, header.method, header.uri,
header.version);

while (TRUE)
{
line = read_line();
if (line.empty())
break;

parse_header_field(line, header);
}
}

void read(BYTE[]& body, HTTP_REQUEST_HEADER& header)
{
string transfer_encoding = header.fields['Transfer-Encoding'];
if (transfer_encoding != b.chunkedb.)
body = read_bytes(header.fields['Content-Length']);
else
{
while (TRUE)
{
string chunk_header = read_line();
DWORD chunk_size = atoi(chunk_header);
if (chunk_size == 0)
break;
BYTE[] chunk_body = read_bytes(chunk_size);
body += chunk_body;
}
}
}

string read_line()
{
while (TRUE)
{
int n = strpos(read_buffer, b.\nb., read_buffer.size());
if (n > 0)
break;
read_buffer += socket.read();
}
return read_buffer.extract(n);
}

Byte[] read_bytes(int sz)
{
while (TRUE)
{
if (sz <= read_buffer.size())
break;
read_buffer += socket.read();
}
return read_buffer.extract(sz);
}

  在这段代码中,执行流程与逻辑流程是一致的,然而,如果在那些被动接收事件的场合使用了异步套接字,就必须编写下面这样的代码了:

read()
{
read_buffer += socket.read();
if (state == read_request_line)
{
if (!read_line(line))
return;
parse_request_link(line, method, uri, version);
state = read_header_field;
}
while (state == read_request_line)
{
if (!read_line(line))
return;
if (line.empty())
{
transfer_encoding = header.fields['Transfer-Encoding'];
if (transfer_encoding != b.chunkedb.)
{
content_length = header.fields['Content-Length'];
state = read_body;
}
else
state = read_chunk_header;
}
else
parse_header_field(line, header, value);
}
if (state == read_body)
{
request_body += read_buffer;
read_buffer.clear();
if (request_body.size() >= content_length)
state = read_finished;
return;
}
if (state == read_chunk_header)
{
if (!read_line(line))
return;
chunk_size = atoi(line);
if (chunk_size == 0)
{
state = read_finished;
return;
}
state = read_body;
}
if (state == read_chunk_body)
{
request_body.append(read_buffer, chunk_size);
if (chunk_size == 0)
state = read_chunk_header;
return;
}
}


  执行流程完全不同了,但逻辑流程却仍保持不变,因为只能一块一块地接收数据,还必须保存状态值及其他变量,以便在事件发生时进行相应的处理。以上只是一些示范性代码,并不能真正工作,在实际中要编写像这样的函数会更加复杂,也更加容易出错

解决方案

  为减少麻烦,可在程序主流程之外再创建一个子过程,这个子过程用于执行某些虚拟逻辑,在需要满足某些条件之后才能继续执行时,它可以先停下来,直到主流程告之它再次进行检查。对于上面的示例,可以写成如下的代码:

class Connection
{
SOCKET socket;
Connection(SOCKET s) : socket(s)
{
FLOW_START conn.flow_start();
}

void flow_start()
{
while (TRUE)
{
HTTP_REQUEST http_request;
try {
read(&http_request);
}
catch (EXCEPTION e)
{
break;
}

FILE file;
fp = fopen(http_request.uri);
if (fp == NULL)
{
write(fp);
fclose(file);
}
else
write(504);
}

socket.close();
delete this;
}

void read(HTTP_REQUEST* http_request)
{
read(&http_request.header);
read(&http_request.body, &http_request.header);
}

void read(HTTP_REQUEST_HEADER* header)
{ …}

void read(BYTE[]& body, HTTP_REQUEST_HEADER& header)
{ …}

string read_line()
{
while (TRUE)
{
FLOW_WAIT (m_buffer += )
char* str = strchr(m_buffer, '\n');
if (!str)
continue;
}

string s(m_buffer, 0, str - m_buffer);
memcpy(m_buffer, str);
buf_avail -= str - m_buffer;
return s;
}

BYTE[] read_bytes(int sz)
{
while (TRUE)
{
WAIT (m_buffer += );
if (m_buffer.length < sz)
continue;
}

BYTE[] data = m_buffer.extract(0, sz);
return data;
}

void write(FILE* fp)
{
int filesize = fp.size();

string header;
header << "200 OK\r\nContent-Length: " << filesize << ";\r\n"
<<"\r\n";
write(header.c_str(), header.size());

int szBulk;
for (int i = 0; i < filesize; i += szBulk)
{
szBulk = min(filesize - i, 8192);
data = fread(fp, szBulk);
write(data, szBulk);
}
}

void write(WORD error_status)
{
string header;
header << error_status << " Error\r\n"
<<"\r\n";
write(header.c_str(), header.size());
}

void write(BYTE[] data, int len)
{
while (len > 0)
{
int ret = socket.write(data, len);
if (ret > 0)
{
data += ret;
len -= ret;
}
if (len)
{
WAIT (bWritable == TRUE);
}
}
}

void OnRead()
{
int avail = socket.avail();
m_buffer += socket.read(avail);
}

void OnWrite()
{
bWritable = TRUE;
}

void OnClose()
{
delete this;
}
};

main {
Socket listen_socket;
listen_socket.listen(http_port);
socket_add(listen_socket, NULL);

socket_loop(socket_callback);
}

void socket_callback(void* user_data, SOCKET s, int msg,
int lParam, void* pParam)
{
switch (msg)
{
case READ:
if (user_data == NULL)
{
SOCKET s2 = accept(s);
Connection conn = new Connection(socket);
socket_add(s2, conn);
break;
}
((Connection*)user_data)->OnRead();
break;

case WRITE:
((Connection*)user_data)->OnWrite();
break;

case EXCEPT:
((Connection*)user_data)->OnExcept();
break;
}
}

  这涉及到两个新的原语:一个为FLOW_START,其创建了一个新的子过程;另一个为FLOW_WAIT,其告之系统何时将被调用以继续程序流程。例如,FLOW_WAIT(m_buffer += )意味着m_buffer的操作符+=被执行,FLOW_WAIT (bWritable = TRUE)意味着bWritable被设为TRUE。

  当一个连接对象创建后,因为FLOW_START这条指令,一个子过程也会被创建,执行流程会沿着此过程执行下去,直至碰到FLOW_WAIT,然后,它会继续执行主流程;当它追加m_buffer或设置bWritable为TRUE时,它将继续执行子过程,直至碰到另一个FLOW_WAIT,此时再返回到主流程当中。

 


TAG:

引用 删除 电影网   /   2007-08-02 18:53:00
```````支持`````````````````
 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

日历

« 2008-09-02  
 123456
78910111213
14151617181920
21222324252627
282930    

数据统计

  • 访问量: 2238
  • 日志数: 100
  • 建立时间: 2007-01-05
  • 更新时间: 2008-04-07

RSS订阅

Open Toolbar