。。。。。。。。。。 (100分)

  • 主题发起人 主题发起人 陈一蛟
  • 开始时间 开始时间
看来,诸位都是大侠,我有一事请教
我刚接触socket,具体是DELPHI自带的Socket组件,现在,我要把ClientSocket封装到
一个类中,把ClientSocket的属性、时间、方法全部封装进去,我的类提供一个Open函数
就是激活封装进去的ClientSocket,它是布尔类型,我如何在ClientSocket是非阻塞模式下
拦截错误提示,能使open得知ClientSocket是否激活;我用阻塞模式可以得到,但是阻塞模
式下客户端发送信息到服务器可以得到,可服务器发送的信息客户端却无法得到,我服务器
端是stNonBlocking模式,望大侠指点一二,不胜感激
 
组塞模式下的错误也是在OnError事件里,你只需要替换这个事件就可以了,
至于C/S之间的通讯和组塞、非组塞是没没有关系的,估计是你的代码有问题
 
我在OnError事件中可以得到,可我是现在是如何把得到错误传给open函数
function Open: boolean;
begin
Result := false;
FClientSocket.open;
//应该是判断是否连接成功
我这部分代码如何编写,如是非阻塞模式,现在是得不到FClientSocket连接情况的
end;
用阻塞模式我在服务器端的OnClientRead事件中监听客户端的信息,如监听到在此事件中
写语句 : socket.sendtext('收到');可客户端却没有反映,望指教
 
组塞下OnClientRead是收不到消息的
 
客户端阻塞模式,在服务器端的OnClientRead可以收到信息,可是客户端的OnRead收不到
信息
 
?组塞下OnRead事件是不能收到消息的
 
>>张无忌
你是什么意思,是确定OnRead收不到消息,还是有疑问
 
to 张无忌:
可以把完成端口的程序的Demo发给我看看吗?
xmodem@citiz.net
 
我上传了 NETWORK.PROGRAMMING.FOR.WINDOWS.2ND 到 Playicq
如果哪位有代码.也上传!
 
。。。。。。。。。。。
 
其实只要有第五章和第六章的 Sample 代码就可以啦
 
。。。。。。。。。。。。。。。。。
 
c1005@263.net
发完毕.
 
。。。。。。。。。。。。。。。
 
张无忌:
把完成端口的程序的Demo发给我一份好吗?我在做这方面工作。
susu4361@sina.com
 
。。。。。。。。。。。。。。。。。。。。。
 
而且我还觉得那个测试有问题的,如果 Network Programming for Microsoft® Windows®
一书的作者所测试的结果真的那么厉害的话,一台 PC Server(Pentium 4 1.7GHzXeon 768 MB)
可以提供响应 5 万个并发连接及数据请求服务的话,为什么到现在 2003 年 HotMail 还是无法
全部使用自己的 Server ,而且如果真的有这么大的效能的话,那 MS 配一台 16 个 CPU 32GB
运行她自己的 DataCenter Server 的服务器,那就可以响应 100 万个的并发请求服务, MS
只需要几十台服务器就可以响应几千万个并发请求服务啦,何必还要几千台服务器啊,维护起来
多麻烦啊!
其实我就是觉得吹嘘的成分比较多啊!

 
我也不太相信完成端口的超强性能,但是,按照他的设计思想,对于很多短时且小数据量
的连接是很合适的。不过,由于我自己还没有做过测试,所以,不能下结论。
 
完全端口. 我总算看到了.在Delphi的书里都没有提到过.

The Completion Port Model
For newcomers, the completion port model seems overwhelmingly complicated because extra work is required to add sockets to a completion port when compared to the initialization steps for the other I/O models. However, as you will see, these steps are not that complicated once you understand them. Also, the completion port model offers the best system performance possible when an application has to manage many sockets at once. Unfortunately, it's available only on Windows NT, Windows 2000, and Windows XP; however, the completion port model offers the best scalability of all the models discussed so far. This model is well suited to handling hundreds or thousands of sockets.

Essentially, the completion port model requires you to create a Windows completion port object that will manage overlapped I/O requests using a specified number of threads to service the completed overlapped I/O requests. Note that a completion port is actually a Windows I/O construct that is capable of accepting more than just socket handles. However, this section will describe only how to take advantage of the completion port model by using socket handles. To begin using this model, you are required to create an I/O completion port object that will be used to manage multiple I/O requests for any number of socket handles. This is accomplished by calling the CreateIoCompletionPort function, which is defined as

HANDLE CreateIoCompletionPort(
HANDLE FileHandle,
HANDLE ExistingCompletionPort,
DWORD CompletionKey,
DWORD NumberOfConcurrentThreads
);
Before examining the parameters in detail, be aware that this function is actually used for two distinct purposes:

To create a completion port object

To associate a handle with a completion port

When you initially create a completion port object, the only parameter of interest is NumberOfConcurrentThreads; the first three parameters are not significant. The NumberOfConcurrentThreads parameter is special because it defines the number of threads that are allowed to execute concurrently on a completion port. Ideally, you want only one thread per processor to service the completion port to avoid thread context switching. The value 0 for this parameter tells the system to allow as many threads as there are processors in the system. The following code creates an I/O completion port.

CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
NULL, 0, 0);
This will return a handle that is used to identify the completion port when a socket handle is assigned to it.

Worker Threads and Completion Ports
After a completion port is successfully created, you can begin to associate socket handles with the object. Before associating sockets, though, you have to create one or more worker threads to service the completion port when socket I/O requests are posted to the completion port object. At this point, you might wonder how many threads should be created to service the completion port. This is actually one of the more complicated aspects of the completion port model because the number needed to service I/O requests depends on the overall design of your application. It's important to note the distinction between number of concurrent threads to specify when calling CreateIoCompletionPort versus the number of worker threads to create; they do not represent the same thing. We recommended previously that you should have the CreateIoCompletionPort function specify one thread per processor to avoid thread context switching. The NumberOfConcurrentThreads parameter of CreateIoCompletionPort explicitly tells the system to allow only n threads to operate at a time on the completion port. If you create more than n worker threads on the completion port, only n threads will be allowed to operate at a time. (Actually, the system might exceed this value for a short amount of time, but the system will quickly bring it down to the value you specify in CreateIoCompletionPort.) You might be wondering why you would create more worker threads than the number specified by the CreateIoCompletionPort call. As we mentioned previously, this depends on the overall design of your application. If one of your worker threads calls a function—such as Sleep or WaitForSingleObject—and becomes suspended, another thread will be allowed to operate in its place. In other words, you always want to have as many threads available for execution as the number of threads you allow to execute in the CreateIoCompletionPort call. Thus, if you expect your worker thread to ever become blocked, it is reasonable to create more worker threads than the value specified in CreateIoCompletionPort's NumberOfConcurrentThreads parameter.

Once you have enough worker threads to service I/O requests on the completion port, you can begin to associate socket handles with the completion port. This requires calling the CreateIoCompletionPort function on an existing completion port and supplying the first three parameters—FileHandle, ExistingCompletionPort, and CompletionKey—with socket information. The FileHandle parameter represents a socket handle to associate with the completion port. The ExistingCompletionPort parameter identifies the completion port to which the socket handle is to be associated with. The CompletionKey parameter identifies per-handle data that you can associate with a particular socket handle. Applications are free to store any type of information associated with a socket by using this key. We call it per-handle data because it represents data associated with a socket handle. It is useful to store the socket handle using the key as a pointer to a data structure containing the socket handle and other socket-specific information. As we will see later in this chapter, the thread routines that service the completion port can retrieve socket-handle–specific information using this key.

Let's begin to construct a basic application framework from what we've described so far. The following example demonstrates how to start developing an echo server application using the completion port model. In this code, we take the following preparation steps:

Create a completion port. The fourth parameter is left as 0, specifying that only one worker thread per processor will be allowed to execute at a time on the completion port.

Determine how many processors exist on the system.

Create worker threads to service completed I/O requests on the completion port using processor information in step 2. In the case of this simple example, we create one worker thread per processor because we do not expect our threads to ever get in a suspended condition in which there would not be enough threads to execute for each processor. When the CreateThread function is called, you must supply a worker routine that the thread executes upon creation. We will discuss the worker thread's responsibilities later in this section.

Prepare a listening socket to listen for connections on port 5150.

Accept inbound connections using the accept function.

Create a data structure to represent per-handle data and save the accepted socket handle in the structure.

Associate the new socket handle returned from accept with the completion port by calling CreateIoCompletionPort. Pass the per-handle data structure to CreateIoCompletionPort via the completion key parameter.

Start processing I/O on the accepted connection. Essentially, you want to post one or more asynchronous WSARecv or WSASend requests on the new socket using the overlapped I/O mechanism. When these I/O requests complete, a worker thread services the I/O requests and continues processing future I/O requests, as we will see later in the worker routine specified in step 3.

Repeat steps 5–8 until server terminates.

HANDLE CompletionPort;
WSADATA wsd;
SYSTEM_INFO SystemInfo;
SOCKADDR_IN InternetAddr;
SOCKET Listen;
int i;

typedef struct _PER_HANDLE_DATA
{
SOCKET Socket;
SOCKADDR_STORAGE ClientAddr;
// Other information useful to be associated with the handle
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;

// Load Winsock
StartWinsock(MAKEWORD(2,2), &wsd);

// Step 1:
// Create an I/O completion port

CompletionPort = CreateIoCompletionPort(
INVALID_HANDLE_VALUE, NULL, 0, 0);

// Step 2:
// Determine how many processors are on the system

GetSystemInfo(&SystemInfo);

// Step 3:
// Create worker threads based on the number of
// processors available on the system. For this
// simple case, we create one worker thread for each
// processor.

for(i = 0; i < SystemInfo.dwNumberOfProcessors; i++)
{
HANDLE ThreadHandle;

// Create a server worker thread, and pass the
// completion port to the thread. NOTE: the
// ServerWorkerThread procedure is not defined
// in this listing.

ThreadHandle = CreateThread(NULL, 0,
ServerWorkerThread, CompletionPort,
0, NULL;

// Close the thread handle
CloseHandle(ThreadHandle);
}

// Step 4:
// Create a listening socket

Listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED);

InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(5150);
bind(Listen, (PSOCKADDR) &InternetAddr,
sizeof(InternetAddr));

// Prepare socket for listening

listen(Listen, 5);

while(TRUE)
{
PER_HANDLE_DATA *PerHandleData=NULL;
SOCKADDR_IN saRemote;
SOCKET Accept;
int RemoteLen;
// Step 5:
// Accept connections and assign to the completion
// port

RemoteLen = sizeof(saRemote);
Accept = WSAAccept(Listen, (SOCKADDR *)&saRemote,
&RemoteLen);

// Step 6:
// Create per-handle data information structure to
// associate with the socket
PerHandleData = (LPPER_HANDLE_DATA)
GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));

printf("Socket number %d connected/n", Accept);
PerHandleData->Socket = Accept;
memcpy(&PerHandleData->ClientAddr, &saRemote, RemoteLen);

// Step 7:
// Associate the accepted socket with the
// completion port

CreateIoCompletionPort((HANDLE) Accept,
CompletionPort, (DWORD) PerHandleData, 0);

// Step 8:
// Start processing I/O on the accepted socket.
// Post one or more WSASend() or WSARecv() calls
// on the socket using overlapped I/O.
WSARecv(...);
}

DWORD WINAPI ServerWorkerThread(LPVOID lpParam)
{
// The requirements for the worker thread will be
// discussed later.
return 0;
}
 
好东东,先收藏^_^
 
后退
顶部