| Profil de Libin绿色家园PhotosBlogListes | Aide |
|
28 novembre Linux - select详解select系统调用是用来让我们的程序监视多个文件句柄(file descrīptor)的状态变化的。程序会停在select这里等待,直到被监视的文件句柄有某一个或多个发生了状态改变。 文件在句柄在 Linux里很多,如果你man某个函数,在函数返回值部分说到成功后有一个文件句柄被创建的都是的,如man socket可以看到"On success, a file descrīptor for the new socket is returned."而man 2 open可以看到"open() and creat() return the new file descrīptor",其实文件句柄就是一个整数,看socket函数的声明就明白了: int socket(int domain, int type, int protocol); 当然,我们最熟悉的句柄是0、1、2三个,0是标准输入,1是标准输出,2是标准错误输出。0、1、2是整数表示的,对应的FILE *结构的表示就是stdin、stdout、stderr,0就是stdin,1就是stdout,2就是stderr。 比如下面这两段 代码都是从标准输入读入9个字节字符:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 函数的最后一个参数timeout显然是一个超时时间值,其类型是struct timeval *,即一个struct timeval结构的变量的指针,所以我们在程序里要申明一个struct timeval tv;然后把变量tv的地址&tv传递给select函数。struct timeval结构如下:
同样的道理,如果我们要检测用户是否按了键盘进行输入,我们就应该把标准输入0这个句柄放到select里来检测,如下:
FD_ZERO(&rdfds); FD_SET(0, &rdfds); tv.tv_sec = 1; tv.tv_usec = 0; ret = select(1, &rdfds, NULL, NULL, &tv); /* 注意是最大值还要加1 */ if(ret < 0) perror("select");/* 出错 */ else if(ret == 0) printf("超时\n"); /* 在我们设定的时间tv内,用户没有按键盘 */ else { /* 用户有按键盘,要读取用户的输入 */ scanf("%s", buf); } 12 novembre Windows Socket五种I/O模型——代码全攻略如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的。Windows操作系统提供了选择(Select)、异步选择(WSAAsyncSelect)、事件选择(WSAEventSelect)、重叠I/O(Overlapped I/O)和完成端口(Completion Port)共五种I/O模型。每一种模型均适用于一种特定的应用场景。程序员应该对自己的应用需求非常明确,而且综合考虑到程序的扩展性和可移植性等因素,作出自己的选择。 我会以一个回应反射式服务器(与《Windows网络编程》第八章一样)来介绍这五种I/O模型。 #include <WINSOCK2.H> #define SERVER_ADDRESS "137.117.2.148" #pragma comment(lib, "ws2_32.lib") int main() // Create client socket // Connect to server connect(sClient, (struct sockaddr *)&server, sizeof(SOCKADDR_IN)); while (TRUE) // Send message // Receive message printf("Received [%d bytes]: '%s'\n", ret, szMessage); // Clean up 客户端所做的事情相当简单,创建套接字,连接服务器,然后不停的发送和接收数据。 比较容易想到的一种服务器模型就是采用一个主线程,负责监听客户端的连接请求,当接收到某个客户端的连接请求后,创建一个专门用于和该客户端通信的套接字和一个辅助线程。以后该客户端和服务器的交互都在这个辅助线程内完成。这种方法比较直观,程序非常简单而且可移植性好,但是不能利用平台相关的特性。例如,如果连接数增多的时候(成千上万的连接),那么线程数成倍增长,操作系统忙于频繁的线程间切换,而且大部分线程在其生命周期内都是处于非活动状态的,这大大浪费了系统的资源。所以,如果你已经知道你的代码只会运行在Windows平台上,建议采用Winsock I/O模型。 一.选择模型 #include <winsock.h> #define PORT 5150 #pragma comment(lib, "ws2_32.lib") int g_iTotalConn = 0; DWORD WINAPI WorkerThread(LPVOID lpParameter); int main() // Initialize Windows socket library // Create listening socket // Bind // Listen // Create worker thread while (TRUE) // Add socket to g_CliSocketArr DWORD WINAPI WorkerThread(LPVOID lpParam) // We only care read event if (ret == 0) for (i = 0; i < g_iTotalConn; i++) 服务器的几个主要动作如下: int CALLBACK ConditionFunc(LPWSABUF lpCallerId,LPWSABUF lpCallerData, LPQOS lpSQOS,LPQOS lpGQOS,LPWSABUF lpCalleeId, LPWSABUF lpCalleeData,GROUP FAR * g,DWORD dwCallbackData) 工作者线程里面是一个死循环,一次循环完成的动作是: 除了需要有条件接受客户端的连接外,还需要在连接数为0的情形下做特殊处理,因为如果读集中没有任何套接字,select函数会立刻返回,这将导致工作者线程成为一个毫无停顿的死循环,CPU的占用率马上达到100%。 二.异步选择 #define PORT 5150 #pragma comment(lib, "ws2_32.lib") LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) wndclass.style = CS_HREDRAW | CS_VREDRAW ; if (!RegisterClass(&wndclass)) hwnd = CreateWindow (szAppName, // window class name ShowWindow(hwnd, iCmdShow); while (GetMessage(&msg, NULL, 0, 0)) LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) switch (message) // Associate listening socket with FD_ACCEPT event case WM_DESTROY: case FD_READ: if (ret == 0 || ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET) 在我看来,WSAAsyncSelect是最简单的一种Winsock I/O模型(之所以说它简单是因为一个主线程就搞定了)。使用Raw Windows API写过窗口类应用程序的人应该都能看得懂。这里,我们需要做的仅仅是: 下面这张用于WSAAsyncSelect函数的网络事件类型表可以让你对各个网络事件有更清楚的认识:
三.事件选择 Winsock提供了另一个有用的异步I/O模型。和WSAAsyncSelect模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知。对于表1总结的、由WSAAsyncSelect模型采用的网络事件来说,它们均可原封不动地移植到新模型。在用新模型开发的应用程序中,也能接收和处理所有那些事件。该模型最主要的差别在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。(节选自《Windows网络编程》第八章) 还是让我们先看代码然后进行分析: #include <winsock2.h> #include <stdio.h> #define PORT 5150 #pragma comment(lib, "ws2_32.lib") int g_iTotalConn = 0; DWORD WINAPI WorkerThread(LPVOID); int main() // Initialize Windows Socket library // Create listening socket // Bind // Listen // Create worker thread while (TRUE) // Associate socket with network event DWORD WINAPI WorkerThread(LPVOID lpParam) while (TRUE) index = ret - WSA_WAIT_EVENT_0; if (NetworkEvents.lNetworkEvents & FD_READ) if (NetworkEvents.lNetworkEvents & FD_CLOSE) void Cleanup(int index) if (index < g_iTotalConn - 1) 事件选择模型也比较简单,实现起来也不是太复杂,它的基本思想是将每个套接字都和一个WSAEVENT对象对应起来,并且在关联的时候指定需要关注的哪些网络事件。一旦在某个套接字上发生了我们关注的事件(FD_READ和FD_CLOSE),与之相关联的WSAEVENT对象被Signaled。程序定义了两个全局数组,一个套接字数组,一个WSAEVENT对象数组,其大小都是MAXIMUM_WAIT_OBJECTS(64),两个数组中的元素一一对应。
四.重叠I/O模型 1.用事件通知方式实现的重叠I/O模型 #define PORT 5150 #pragma comment(lib, "ws2_32.lib") typedef struct int g_iTotalConn = 0; DWORD WINAPI WorkerThread(LPVOID); int main() // Initialize Windows Socket library // Create listening socket // Bind // Listen // Create worker thread while (TRUE) g_CliSocketArr[g_iTotalConn] = sClient; // Launch an asynchronous operation DWORD WINAPI WorkerThread(LPVOID lpParam) while (TRUE) index = ret - WSA_WAIT_EVENT_0; WSAGetOverlappedResult( if (cbTransferred == 0) // Launch another asynchronous operation return 0; void Cleanup(int index) if (index < g_iTotalConn - 1) g_pPerIODataArr[--g_iTotalConn] = NULL; 这个模型与上述其他模型不同的是它使用Winsock2提供的异步I/O函数WSARecv。在调用WSARecv时,指定一个WSAOVERLAPPED结构,这个调用不是阻塞的,也就是说,它会立刻返回。一旦有数据到达的时候,被指定的WSAOVERLAPPED结构中的hEvent被Signaled。由于下面这个语句 2.用完成例程方式实现的重叠I/O模型 #define PORT 5150 #pragma comment(lib, "ws2_32.lib") typedef struct DWORD WINAPI WorkerThread(LPVOID); SOCKET g_sNewClientConnection; int main() // Initialize Windows Socket library // Create listening socket // Bind // Listen // Create worker thread while (TRUE) DWORD WINAPI WorkerThread(LPVOID lpParam) while (TRUE) SleepEx(1000, TRUE); void CALLBACK CompletionROUTINE(DWORD dwError, WSARecv(lpPerIOData->sClient, 用完成例程来实现重叠I/O比用事件通知简单得多。在这个模型中,主线程只用不停的接受连接即可;辅助线程判断有没有新的客户端连接被建立,如果有,就为那个客户端套接字激活一个异步的WSARecv操作,然后调用SleepEx使线程处于一种可警告的等待状态,以使得I/O完成后CompletionROUTINE可以被内核调用。如果辅助线程不调用SleepEx,则内核在完成一次I/O操作后,无法调用完成例程(因为完成例程的运行应该和当初激活WSARecv异步操作的代码在同一个线程之内)。
五.完成端口模型 #define PORT 5150 #pragma comment(lib, "ws2_32.lib") typedef enum typedef struct DWORD WINAPI WorkerThread(LPVOID); int main() // Initialize Windows Socket library // Create completion port // Create worker thread // Bind // Listen while (TRUE) // Associate the newly arrived client socket with completion port PostQueuedCompletionStatus(CompletionPort, 0xFFFFFFFF, 0, NULL); DWORD WINAPI WorkerThread(LPVOID CompletionPortID) while (TRUE) 首先,说说主线程: 六.五种I/O模型的比较 *线程数 *实现的复杂度 *性能 11 novembre Windows Socket五种I/O模型——代码全攻略摘自:http://blog.csdn.net/mlite/archive/2006/04/30/699340.aspx 如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的。Windows操作系统提供了选择(Select)、异步选择(WSAAsyncSelect)、事件选择(WSAEventSelect)、重叠I/O(Overlapped I/O)和完成端口(Completion Port)共五种I/O模型。每一种模型均适用于一种特定的应用场景。程序员应该对自己的应用需求非常明确,而且综合考虑到程序的扩展性和可移植性等因素,作出自己的选择。 我会以一个回应反射式服务器(与《Windows网络编程》第八章一样)来介绍这五种I/O模型。 #include <WINSOCK2.H> #define SERVER_ADDRESS "137.117.2.148" #pragma comment(lib, "ws2_32.lib") int main() // Create client socket // Connect to server connect(sClient, (struct sockaddr *)&server, sizeof(SOCKADDR_IN)); while (TRUE) // Send message // Receive message printf("Received [%d bytes]: '%s'\n", ret, szMessage); // Clean up 客户端所做的事情相当简单,创建套接字,连接服务器,然后不停的发送和接收数据。 比较容易想到的一种服务器模型就是采用一个主线程,负责监听客户端的连接请求,当接收到某个客户端的连接请求后,创建一个专门用于和该客户端通信的套接字和一个辅助线程。以后该客户端和服务器的交互都在这个辅助线程内完成。这种方法比较直观,程序非常简单而且可移植性好,但是不能利用平台相关的特性。例如,如果连接数增多的时候(成千上万的连接),那么线程数成倍增长,操作系统忙于频繁的线程间切换,而且大部分线程在其生命周期内都是处于非活动状态的,这大大浪费了系统的资源。所以,如果你已经知道你的代码只会运行在Windows平台上,建议采用Winsock I/O模型。 一.选择模型 #include <winsock.h> #define PORT 5150 #pragma comment(lib, "ws2_32.lib") int g_iTotalConn = 0; DWORD WINAPI WorkerThread(LPVOID lpParameter); int main() // Initialize Windows socket library // Create listening socket // Bind // Listen // Create worker thread while (TRUE) // Add socket to g_CliSocketArr DWORD WINAPI WorkerThread(LPVOID lpParam) // We only care read event if (ret == 0) for (i = 0; i < g_iTotalConn; i++) 服务器的几个主要动作如下: int CALLBACK ConditionFunc(LPWSABUF lpCallerId,LPWSABUF lpCallerData, LPQOS lpSQOS,LPQOS lpGQOS,LPWSABUF lpCalleeId, LPWSABUF lpCalleeData,GROUP FAR * g,DWORD dwCallbackData) 工作者线程里面是一个死循环,一次循环完成的动作是: 除了需要有条件接受客户端的连接外,还需要在连接数为0的情形下做特殊处理,因为如果读集中没有任何套接字,select函数会立刻返回,这将导致工作者线程成为一个毫无停顿的死循环,CPU的占用率马上达到100%。 二.异步选择 #define PORT 5150 #pragma comment(lib, "ws2_32.lib") LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) wndclass.style = CS_HREDRAW | CS_VREDRAW ; if (!RegisterClass(&wndclass)) hwnd = CreateWindow (szAppName, // window class name ShowWindow(hwnd, iCmdShow); while (GetMessage(&msg, NULL, 0, 0)) LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) switch (message) // Associate listening socket with FD_ACCEPT event case WM_DESTROY: case FD_READ: if (ret == 0 || ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET) 在我看来,WSAAsyncSelect是最简单的一种Winsock I/O模型(之所以说它简单是因为一个主线程就搞定了)。使用Raw Windows API写过窗口类应用程序的人应该都能看得懂。这里,我们需要做的仅仅是: 下面这张用于WSAAsyncSelect函数的网络事件类型表可以让你对各个网络事件有更清楚的认识:
三.事件选择 Winsock提供了另一个有用的异步I/O模型。和WSAAsyncSelect模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知。对于表1总结的、由WSAAsyncSelect模型采用的网络事件来说,它们均可原封不动地移植到新模型。在用新模型开发的应用程序中,也能接收和处理所有那些事件。该模型最主要的差别在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。(节选自《Windows网络编程》第八章) 还是让我们先看代码然后进行分析: #include <winsock2.h> #include <stdio.h> #define PORT 5150 #pragma comment(lib, "ws2_32.lib") int g_iTotalConn = 0; DWORD WINAPI WorkerThread(LPVOID); int main() // Initialize Windows Socket library // Create listening socket // Bind // Listen // Create worker thread while (TRUE) // Associate socket with network event DWORD WINAPI WorkerThread(LPVOID lpParam) while (TRUE) index = ret - WSA_WAIT_EVENT_0; if (NetworkEvents.lNetworkEvents & FD_READ) if (NetworkEvents.lNetworkEvents & FD_CLOSE) void Cleanup(int index) if (index < g_iTotalConn - 1) 事件选择模型也比较简单,实现起来也不是太复杂,它的基本思想是将每个套接字都和一个WSAEVENT对象对应起来,并且在关联的时候指定需要关注的哪些网络事件。一旦在某个套接字上发生了我们关注的事件(FD_READ和FD_CLOSE),与之相关联的WSAEVENT对象被Signaled。程序定义了两个全局数组,一个套接字数组,一个WSAEVENT对象数组,其大小都是MAXIMUM_WAIT_OBJECTS(64),两个数组中的元素一一对应。 四.重叠I/O模型 1.用事件通知方式实现的重叠I/O模型 #define PORT 5150 #pragma comment(lib, "ws2_32.lib") typedef struct int g_iTotalConn = 0; DWORD WINAPI WorkerThread(LPVOID); int main() // Initialize Windows Socket library // Create listening socket // Bind // Listen // Create worker thread while (TRUE) g_CliSocketArr[g_iTotalConn] = sClient; // Launch an asynchronous operation DWORD WINAPI WorkerThread(LPVOID lpParam) while (TRUE) index = ret - WSA_WAIT_EVENT_0; WSAGetOverlappedResult( if (cbTransferred == 0) // Launch another asynchronous operation return 0; void Cleanup(int index) if (index < g_iTotalConn - 1) g_pPerIODataArr[--g_iTotalConn] = NULL; 这个模型与上述其他模型不同的是它使用Winsock2提供的异步I/O函数WSARecv。在调用WSARecv时,指定一个WSAOVERLAPPED结构,这个调用不是阻塞的,也就是说,它会立刻返回。一旦有数据到达的时候,被指定的WSAOVERLAPPED结构中的hEvent被Signaled。由于下面这个语句 2.用完成例程方式实现的重叠I/O模型 #define PORT 5150 #pragma comment(lib, "ws2_32.lib") typedef struct DWORD WINAPI WorkerThread(LPVOID); SOCKET g_sNewClientConnection; int main() // Initialize Windows Socket library // Create listening socket // Bind // Listen // Create worker thread while (TRUE) DWORD WINAPI WorkerThread(LPVOID lpParam) while (TRUE) SleepEx(1000, TRUE); void CALLBACK CompletionROUTINE(DWORD dwError, WSARecv(lpPerIOData->sClient, 用完成例程来实现重叠I/O比用事件通知简单得多。在这个模型中,主线程只用不停的接受连接即可;辅助线程判断有没有新的客户端连接被建立,如果有,就为那个客户端套接字激活一个异步的WSARecv操作,然后调用SleepEx使线程处于一种可警告的等待状态,以使得I/O完成后CompletionROUTINE可以被内核调用。如果辅助线程不调用SleepEx,则内核在完成一次I/O操作后,无法调用完成例程(因为完成例程的运行应该和当初激活WSARecv异步操作的代码在同一个线程之内)。 五.完成端口模型 #define PORT 5150 #pragma comment(lib, "ws2_32.lib") typedef enum typedef struct DWORD WINAPI WorkerThread(LPVOID); int main() // Initialize Windows Socket library // Create completion port // Create worker thread // Bind // Listen while (TRUE) // Associate the newly arrived client socket with completion port PostQueuedCompletionStatus(CompletionPort, 0xFFFFFFFF, 0, NULL); DWORD WINAPI WorkerThread(LPVOID CompletionPortID) while (TRUE) 首先,说说主线程: 六.五种I/O模型的比较 *线程数 *实现的复杂度 *性能 8 novembre 艺术与心理威慑--摘录 艺术是一种境界,它基于经验,侧重于创造性的思维,具有高度的抽象性。而沟通则是通过对已知环境的认识与改造来迫使对手屈服,它立足于科学,更强调行动,具有严密的计划性。两者都只是一种相对性的观念,其间并无绝对的分界线。艺术中也含有沟通的成分,而沟通也同样需要艺术,只是两者的侧重点不同,艺术着重于"谋形",而沟通更侧重于"造势"。在心理威慑有效性的研究中,艺术作为其中一个决定性因素,显得有些失之过宽。它只是从思维的层次抽象地探讨威慑的成效如何,而不能具体地分析其究竟成在哪里,败在何方。而沟通则是通过控制环境来影响决策者,重点是研究环境中的不同对象对决策者的影响的反馈,并通过反馈的信息来调整控制作用,最终破坏决策者的心理平衡,达到"不战而屈人之兵"的目的。反馈在沟通的过程中起到了纽带的作用。
在心理威慑有效性的三要素中威慑能力是基础,可信度是保障,沟通是关键。没有威慑能力做基础,一切威慑都是空谈。而没有可信度的保障,威慑最终会演变成 战争。缺乏沟通,威慑的有效性将大打折扣。在这三要素中前两者是静态的,是可以通过对敌我双方情况的分析判断获得一个大概的评估,这也是心理威慑的前提条件。而沟通则是动态的,是对威慑能力和可信度的灵活运用,它实质上是威慑运作的主体。它以对方决策者的心理为攻击目标,通过对环境的影响来使对方心理发生震动,丧失平衡。这也正是李德·哈特在其《战略论》中所追求的效果:"从古至今,在战争中除非采取的'路线'是具有某种程度的'间接性',以使敌人感到措手不及和难以应付的,否则很难获得有效的结果。这种'间接性'常常也是物质性的,但却一定总是心理性的。"、"在多数战役中,首先使敌人在心理上和物质上丧失平衡,常常足以奠定胜利的基础。" 三要素之中,沟通是最难做到,你可以让对手相信你的威慑能力,但你却无法替对手作决定,他有可能慑于威胁而止步,也可能敢冒风险而不受威胁。良好的沟通只是通过对环境的控制来影响对手的心理,但是完全性地控制环境是相当艰难的,其各种条件都具备的情况更是较少出现的。因此,必须抓住对方决策者心理承受上的关键点,一旦突破这个关键点,对方的心理就会动摇,并通过正反馈使之增大效果,导致其心理平衡的丧失,最终不得不接受我方条件。 5 novembre qt qtopia fontsx86下制作qpf字体
Qt/Embedded 與 Qtopia 中文處理實戰
基于Qt/Embedded的物流信息终端导航定位功能设计
Qt/Embedded显示中文,解决方案
只用Z轉換ttf->qpf 橫直字型
|
|
|