在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: