net programming for microsoft windows 读书笔记
2010-04-03 11:16
513 查看
>
socket modes
socket modes
As we mentioned, Windows sockets perform I/O operations in two socket operating modes: blocking
Once a socket is placed in non-blocking mode(by calling the ioctlsocket()), Winsock API calls that deal with sending and receiving data or connection management return immediately. In most cases, these calls fail with the error WSAEWOULDBLOCK
socket I/O models(管理多个sockets的方法)
We call it the select
The select
int select(
Winsock provides a useful asynchronous I/O model that allows an application to
To use the WSAAsyncSelect
Once you have set up the window infrastructure, you can begin creating sockets
int WSAAsyncSelect(
The s
The hWnd
The wMsg
The last parameter, lEvent
WSAAsyncSelect(s, hwnd, WM_SOCKET, FD_CONNECT │ FD_READ │ FD_WRITE │ FD_CLOSE);
This allows our application to get connect, send, receive,
When your application calls WSAAsyncSelect
LRESULT CALLBACK WindowProc(
The hWnd
The uMsg
The wParam
The lParam
When network event messages arrive at a window procedure, the
One final detail worth noting is how applications should process
After a socket is first connected with connect or WSAConnect
After a socket is accepted with accept or WSAAccept
When a send, WSASend
Therefore, an application should assume that sends are
The WSAAsyncSelect
Winsock provides another useful asynchronous event notification
The event notification model requires your application to create
The WSACreateEvent
int WSAEventSelect(
The s
The hEventObject
The last parameter, lNetworkEvents
The event created for WSAEventSelect
Because the event object is created in a manual reset mode, your application is
BOOL WSAResetEvent(WSAEVENT hEvent);
The function takes an event handle as its only parameter
When an application is finished with an event object, it should call the WSACloseEvent
This function also takes an event handle as its only
Once a socket is associated with an event object handle, the
DWORD WSAWaitForMultipleEvents(
The cEvents
If you need to have this model manage more than 64 sockets, you should create
The fWaitAll
If TRUE
The dwTimeout
The final parameter, fAlertable
Note that by servicing signaled events one at a time (by setting the fWaitAll
This is clearly undesirable. Once an event within the loop is signaled and
When WSAWaitForMultipleEvents
Index = WSAWaitForMultipleEvents(...);
int WSAEnumNetworkEvents(
The s
typedef struct _WSANETWORKEVENTS
More than one network event type can occur whenever an event is
The iErrorCode
// Process FD_READ notification
After you process the events in the WSANETWORKEVENTS
SOCKET SocketArray [WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT EventArray [WSA_MAXIMUM_WAIT_EVENTS],
SOCKADDR_IN InternetAddr;
SOCKET Accept, Listen;
DWORD EventTotal = 0;
DWORD Index, i;
// Set up a TCP socket for listening on port 5150
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(5150);
bind(Listen, (PSOCKADDR) &InternetAddr,
NewEvent = WSACreateEvent();
WSAEventSelect(Listen, NewEvent,
listen(Listen, 5);
SocketArray[EventTotal] = Listen;
EventTotal++;
while(TRUE)
// Wait for network events on all sockets
Index = WSAWaitForMultipleEvents(EventTotal,
{
Index = WSAWaitForMultipleEvents(1, &EventArray[i], TRUE, 1000,
if ((Index == WSA_WAIT_FAILED) ││ (Index == WSA_WAIT_TIMEOUT))
{
break;
// socket and event lists
Accept = accept(
// We cannot process more than
// WSA_MAXIMUM_WAIT_EVENTS sockets, so close
// Process FD_READ notification
if (NetworkEvents.lNetworkEvents & FD_READ)
recv(SocketArray[Index - WSA_WAIT_EVENT_0],
{
其实上例中的for循环可以不存在,只不过如果那样的话,如果第一个socket一直有event发生的话,那么数组中后边的socket总是很不到机会.
The overlapped I/O model in Winsock offers applications better system
The overlapped model's basic design allows your application to post one or more
At a later point, the application can service the submitted requests after they
To use the overlapped I/O model on a socket, you must first create a socket that
After you successfully create a socket and bind it to a local
WSASend
WSASendTo
WSARecv
WSARecvFrom
WSAIoctl
WSARecvMsg
AcceptEx
ConnectEx
TransmitFile
TransmitPackets
DisconnectEx
WSANSPIoctl
To use overlapped I/O, each function takes a WSAOVERLAPPED
When these functions are called with a WSAOVERLAPPED
They rely on the WSAOVERLAPPED
There are essentially two methods for managing the completion of an overlapped
The first six functions in the list have another parameter in common: a WSAOVERLAPPED_COMPLETION_ROUTINE
The event notification method of overlapped I/O requires associating Windows
When I/O calls such as WSASend
Typically, you will find that these I/O calls fail with the return value SOCKET_ERROR
At a later time, your application will need to determine when an overlapped I/O
The WSAOVERLAPPED
typedef struct WSAOVERLAPPED
The Internal, InternalHigh,
When an overlapped I/O request finally completes, your application is
Once you determine which overlapped request has completed, you need to determine
BOOL WSAGetOverlappedResult(
The s
The lpOverlapped
The lpcbTransfer
The fWait
If fWait
如何写一个高性能的可应对多个连接的c/s程序:
The only I/O model that provides true scalability on Windows NT platforms is overlapped I/O using completion ports for notification
难以理解的知识点
if ((NewConnection = accept(ListeningSocket, (SOCKADDR *) &ClientAddr,&ClientAddrLen)) == INVALID_SOCKET)
WINDOWS下的防火墙技术都被研究得比较透了
socket modes
和socket I/O models
.
socket modes
(每一个socket对象自己所具备的特性
):
As we mentioned, Windows sockets perform I/O operations in two socket operating modes: blocking
and non-blocking
. In blocking mode, Winsock calls that perform I/O—such as send
and recv—
wait until the operation is complete before they return to the program. In non-blocking mode, the Winsock functions return immediately.
Once a socket is placed in non-blocking mode(by calling the ioctlsocket()), Winsock API calls that deal with sending and receiving data or connection management return immediately. In most cases, these calls fail with the error WSAEWOULDBLOCK
, which means that the requested operation did not have time to complete during the call. For example, a call to recv
returns WSAEWOULDBLOCK
if no data is pending in the system's input buffer. Often additional calls to the same function are required until it encounters a successful return code.
socket I/O models(管理多个sockets的方法)
:
对于一个socket,我们可以使用blocking or non-blocking mode去处理.
当有多个socket时怎么办?
1 可以使用blocking socket加多线程的方法来处理,即每一个线程来处理一个socket的操作. 这样做的缺点是太多的线程浪费系统资源而且影响系统效率.
2 如果使用non-blocking方式来处理, 但是随着sockets个数的增多, 程序要用不断循环的方法来调用函数直到他们成功, 程序变得无法管理.所以这个模式不存在.
3 select模型.
4 WSAAsyncSelect模型.
5 WSAEventSelect模型.
6 overlapped 模型.
7 completion port
详解模型:
1 blocking socket + 多线程.
这种模式的好处是简单,容易实现. 坏处是因为要为每个socket创建一个或者两个线程来对它进行处理.所以非常浪费系统资源, 这里所说的系统资源是内存, 包括物理内存和虚拟内存. 每创建一个线程,系统要为线程在虚拟内存中保留1M的栈(这个操作使用了虚拟内存,每一个只有2GB的地址空间是属于用户的.), 而且还要为其中的一些虚拟内存分配一部分物理内存(计算机上的RAM).况且在运行时由于频繁的线程切换会使CPU很累.
2 select模型
We call it the select
model because it centers on using the select
function to manage I/O.
The select
function can be used to determine if there is data on a socket and if a socket can be written to. The reason for having this function is to prevent your application from blocking on an I/O bound call such as send
or recv
when a socket is in a blocking mode and to prevent the WSAEWOULDBLOCK
error when a socket is in a non-blocking mode. The select
function blocks for I/O operations until the conditions specified as parameters are met.
int select(
int nfds,
fd_set FAR * readfds,
fd_set FAR * writefds,
fd_set FAR * exceptfds,
const struct timeval FAR * timeout
);
书中说的不详细, 还有很多的疑问要在msdn中才能找到答案.
比如在 readfds中的socket, 在满足以下三种情况时,认为可以操作。
1 当该socket上有数据可以被读取的时候。2 当该socket被关闭的时候。 3 当有连接请求要连接到该socket 时。
那么在该模型中并没有任何数据用来区别这三种情况,这三种情况中的任意一个发生时,都只是返回一个1而已。
区分的方法是: 如果在readfds中的socket处于listen状态但是没有调用accept时,那么这时肯定是有连接请求到达该socket,此时去accept的话,不会blocking. 如果在readfds中的socket已经是accept过的了,那么肯定是1或者2,那么怎么区别这两种情况呢,方法是直接调用recv函数,如果是1的情况,会成功收到数据。如果是2的情况,会返回一个错误值。
怎么用这个模式来处理多个链接呢?
用一个链表来保存接收到的socket, 用多线程,其中一个线程负责accept链接,得到socket后加入到链表中去.另外一个线程中while(true)一直调用select. 在select之前,每次都检查链表,如果有新socket加入,则把它也加到fd_read中去.
3 WSAAsyncSelect模型
Winsock provides a useful asynchronous I/O model that allows an application to
receive Windows message–based notification of network events on a socket.This is accomplished by calling the WSAAsyncSelect
function after creating a socket.
To use the WSAAsyncSelect
model, your
application must first create a window using the CreateWindow
function and supply a window procedure
(winproc
) support function for it. You can also use a dialog box with a dialog procedure instead of a window
because dialog boxes are
windows.
Once you have set up the window infrastructure, you can begin creating sockets
and turning on window message notification by calling the WSAAsyncSelect
function, which is defined as
int WSAAsyncSelect(
SOCKET s,
HWND hWnd,
unsigned int wMsg,
long lEvent
);
The s
parameter
represents the socket we are interested in.
The hWnd
parameter is a window handle
identifying the window or the dialog box that receives a message when a network
event occurs.
The wMsg
parameter identifies the message to
be received when a network event occurs.
The last parameter, lEvent
, represents a
bitmask that specifies a combination of network events
WSAAsyncSelect(s, hwnd, WM_SOCKET, FD_CONNECT │ FD_READ │ FD_WRITE │ FD_CLOSE);
当有connect,或fd_read,或fd_write,或fd_close这类的网络事件发生的时候, hwnd会收到一个WM_SOCKET事件, 而且在其中又可以根据lparam
来判断是哪一种事件.
This allows our application to get connect, send, receive,
and socket-closure network event notifications on socket s
. It is impossible to register multiple events one
at a time on the socket. Also note that once you turn on event notification on a
socket, it remains on unless the socket is closed by a call to closesocket
or the application changes the
registered network event types by calling WSAAsyncSelect
(again, on the socket). Setting the
lEvent
parameter to 0 effectively stops all
network event notification on the socket.
When your application calls WSAAsyncSelect
on
a socket, the socket mode is automatically changed from blocking to the
non-blocking mode that we described previously(why?
).
How to design the windows procedure?
A window procedure is normally defined as
LRESULT CALLBACK WindowProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
The hWnd
parameter is a
handle to the window that invoked the window procedure.
The uMsg
parameter indicates which message
needs to be processed. In your case, you will be looking for the message defined
in the WSAAsyncSelect
call.
The wParam
parameter identifies the socket on
which a network event has occurred. This is important if you have more than one
socket assigned to this window procedure.
The lParam
parameter contains two important
pieces of information—the low word of lParam
specifies the network event that has occurred, and the high word of lParam
contains any error code.
When network event messages arrive at a window procedure, the
application should first check the lParam
high-word bits to determine whether a network error has occurred on the socket.
There is a special macro, WSAGETSELECTERROR
,
that returns the value of the high-word bits error information. After the
application has verified that no error occurred on the socket, the application
should determine which network event type caused the Windows message to fire by
reading the low-word bits of lParam
. Another
special macro, WSAGETSELECTEVENT
, returns the
value of the low-word portion of lParam
.
One final detail worth noting is how applications should process
FD_WRITE
event notifications. FD_WRITE
notifications are sent under only three
conditions:
After a socket is first connected with connect or WSAConnect
After a socket is accepted with accept or WSAAccept
When a send, WSASend
, sendto
, or WSASendTo
operation fails with WSAEWOULDBLOCK
and buffer space becomes
available
Therefore, an application should assume that sends are
always possible on a socket starting from the first FD_WRITE
message and lasting until a send
, WSASend
,
sendto
, or WSASendTo
returns the socket error WSAEWOULDBLOCK
. After such failure, another FD_WRITE
message notifies the application that sends
are once again possible.
The WSAAsyncSelect
model
offers many advantages; foremost is the capability to handle many connections
simultaneously without much overhead, unlike the select model's requirement of
setting up the fd_set
structures. The
disadvantages are having to use a window if your application requires no windows
(such as a service or console application). Also, having a single window
procedure to service all the events on thousands of socket handles can become a
performance bottleneck (meaning this model doesn't scale very well).
4 the WSAEventSelect model
Winsock provides another useful asynchronous event notification
I/O model that is similar to the WSAAsyncSelect
model that allows an application to
receive event-based notification of network events on one or more sockets. This
model is similar to the WSAAsyncSelect
model
because your application receives and processes the same network events listed
in Table 5-3 that the WSAAsyncSelect
model
uses. The major difference with this model is that network events are notified
via an event object handle instead of a window procedure.
The event notification model requires your application to create
an event object for each socket used by calling the WSACreateEvent
function, which is defined as WSAEVENT WSACreateEvent(void);
The WSACreateEvent
function simply returns a
manual reset event object handle. Once you have an event object handle, you have
to associate it with a socket and register the network event types of interest
int WSAEventSelect(
SOCKET s,
WSAEVENT hEventObject,
long lNetworkEvents
);
The s
parameter
represents the socket of interest.
The hEventObject
parameter represents the
event object—obtained with WSACreateEvent—
to
associate with the socket.
The last parameter, lNetworkEvents
, represents
a bitmask that specifies a combination of network event types that the application is interested in.
The event created for WSAEventSelect
has two
operating states and two operating modes. The operating states are known as signaled
and
non-signaled
. The operating modes are known as manual
reset
and auto
reset
.WSACreateEvent
initially creates event handles
in a non-signaled operating state with a manual reset operating mode.As network events trigger an event object associated with a socket, the
operating state changes from non-signaled to signaled.
Because the event object is created in a manual reset mode, your application is
responsible for changing the operating state from signaled to non-signaled after
processing an I/O request. This can be accomplished by calling the WSAResetEvent
function, which is defined as
BOOL WSAResetEvent(WSAEVENT hEvent);
The function takes an event handle as its only parameter
and returns TRUE
or FALSE
based on the success or failure of the call.
When an application is finished with an event object, it should call the WSACloseEvent
function to free the system resources
used by an event handle. The WSACloseEvent
function is defined as BOOL WSACloseEvent(WSAEVENT hEvent);
This function also takes an event handle as its only
parameter and returns TRUE
if successful or
FALSE
if the call fails.
Once a socket is associated with an event object handle, the
application can begin processing I/O by waiting for network events to trigger
the operating state of the event object handle. The WSAWaitForMultipleEvents
function is designed to
wait on one or more event object handles and returns either when one or all of
the specified handles are in the signaled state or when a specified timeout
interval expires. WSAWaitForMultipleEvents
is
defined as
DWORD WSAWaitForMultipleEvents(
DWORD cEvents,
const WSAEVENT FAR * lphEvents,
BOOL fWaitAll,
DWORD dwTimeout,
BOOL fAlertable
);
The cEvents
and lphEvents
parameters define an array of WSAEVENT
objects in which cEvents
is the number of event objects in the array
and lphEvents
is a pointer to the array. WSAWaitForMultipleEvents
can support only a maximum
of WSA_MAXIMUM_WAIT_EVENTS
objects, which is
defined as 64. Therefore, this I/O model is capable of supporting only a maximum
of 64 sockets at a time for each thread that makes the WSAWaitForMultipleEvents
call.
If you need to have this model manage more than 64 sockets, you should create
additional worker threads to wait on more event objects.
The fWaitAll
parameter specifies how WSAWaitForMultipleEvents
waits for objects in the
event array.
If TRUE
, the function returns when all event
objects in the lphEvents
array are signaled.
If FALSE
, the function returns when any one of
the event objects is signaled. In the latter case, the return value indicates
which event object caused the function to return. Typically, applications set
this parameter to FALSE
and service one socket
event at a time.
The dwTimeout
parameter specifies how long (in
milliseconds) WSAWaitForMultipleEvents
will
wait for a network event to occur.
The final parameter, fAlertable
, can be
ignored when you're using the WSAEventSelect
model and should be set to FALSE
. It is
intended for use in processing completion routines in the overlapped I/O model,
which will be described later in this chapter.
Note that by servicing signaled events one at a time (by setting the fWaitAll
parameter to FALSE
), it is possible to starve sockets toward the
end of the event array.(这是WSAEventSelect一项缺点)
This is clearly undesirable. Once an event within the loop is signaled and
handled, all events in the array should be checked to see if they are signaled
as well. This can be accomplished by using WSAWaitForMultipleEvents
with each individual event
handle after the first signaled event and specifying a dwTimeOut
of zero.
When WSAWaitForMultipleEvents
receives network
event notification of an event object, it returns a value indicating the event
object that caused the function to return. As a result, your application can
determine which network event type is available on a particular socket by
referencing the signaled event in the event array and matching it with the
socket associated with the event. When you reference the events in the event
array, you should reference them using the return value of WSAWaitForMultipleEvents
minus the predefined value
WSA_WAIT_EVENT_0
.
For example:
Index = WSAWaitForMultipleEvents(...);
MyEvent = EventArray[Index - WSA_WAIT_EVENT_0];
Once you have the socket that caused the network event, you can determine which
network events are available by calling the WSAEnumNetworkEvents
function,
which is defined as
int WSAEnumNetworkEvents(
SOCKET s,
WSAEVENT hEventObject,
LPWSANETWORKEVENTS lpNetworkEvents
);
The s
parameter
represents the socket that caused the network event, and the hEventObject
parameter is an optional parameter
representing an event handle identifying an associated event object to be reset.
Because our event object is in a signaled state, we can pass it in and it will
be set to a non-signaled state. The hEventObject
parameter is optional in case you wish to reset the event manually via
the WSAResetEvent
function. The final
parameter, lpNetworkEvents
, takes a pointer to
a WSANETWORKEVENTS
structure, which is used to
retrieve network event types that occurred on the socket and any associated
error codes. The WSANETWORKEVENTS
structure is
defined as
typedef struct _WSANETWORKEVENTS
{
long lNetworkEvents;
int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
注意:
More than one network event type can occur whenever an event is
signaled. For example, a busy server application might receive FD_READ
and FD_WRITE
notification at the same time.
The iErrorCode
parameter is an
array of error codes associated with the events in lNetworkEvents
. For each network event type, there
is a special event index similar to the event type names—except for an
additional “_BIT” string appended to the event name. For example, for the FD_READ
event type, the index identifier for the
iErrorCode
array is named FD_READ_BIT
. The following code fragment
demonstrates this for an FD_READ
event:
// Process FD_READ notification
if (NetworkEvents.lNetworkEvents & FD_READ)
{
if (NetworkEvents.iErrorCode[FD_READ_BIT] != 0)
{
printf("FD_READ failed with error %d/n",
NetworkEvents.iErrorCode[FD_READ_BIT]);
}
}
After you process the events in the WSANETWORKEVENTS
structure, your application should
continue waiting for more network events on all of the available sockets. The
following example demonstrates how to develop a server and manage event objects
when using the WSAEventSelect
I/O model. The
code highlights the steps needed to develop a basic server application capable
of managing one or more sockets at a time.
SOCKET SocketArray [WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT EventArray [WSA_MAXIMUM_WAIT_EVENTS],
NewEvent;
SOCKADDR_IN InternetAddr;
SOCKET Accept, Listen;
DWORD EventTotal = 0;
DWORD Index, i;
// Set up a TCP socket for listening on port 5150
Listen = socket (PF_INET, SOCK_STREAM, 0);
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(5150);
bind(Listen, (PSOCKADDR) &InternetAddr,
sizeof(InternetAddr));
NewEvent = WSACreateEvent();
WSAEventSelect(Listen, NewEvent,
FD_ACCEPT │ FD_CLOSE);
listen(Listen, 5);
SocketArray[EventTotal] = Listen;
EventArray[EventTotal] = NewEvent;
EventTotal++;
while(TRUE)
{
// Wait for network events on all sockets
Index = WSAWaitForMultipleEvents(EventTotal,
EventArray, FALSE, WSA_INFINITE, FALSE);
Index = Index - WSA_WAIT_EVENT_0;
// Iterate through all events to see if more than one is signaled
for(i=Index; i < EventTotal ;i++)
{
Index = WSAWaitForMultipleEvents(1, &EventArray[i], TRUE, 1000,
FALSE);
if ((Index == WSA_WAIT_FAILED) ││ (Index == WSA_WAIT_TIMEOUT))
continue;
else
{
Index = i;
WSAEnumNetworkEvents(
SocketArray[Index],
EventArray[Index],
&NetworkEvents);
// Check for FD_ACCEPT messages
if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
{
if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
{
printf("FD_ACCEPT failed with error %d/n",
NetworkEvents.iErrorCode[FD_ACCEPT_BIT]);
break;
}
// Accept a new connection, and add it to the
// socket and event lists
Accept = accept(
SocketArray[Index],
NULL, NULL);
// We cannot process more than
// WSA_MAXIMUM_WAIT_EVENTS sockets, so close
// the accepted socket
if (EventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
printf("Too many connections");
closesocket(Accept);
break;
}
NewEvent = WSACreateEvent();
WSAEventSelect(Accept, NewEvent,
FD_READ │ FD_WRITE │ FD_CLOSE);
EventArray[EventTotal] = NewEvent;
SocketArray[EventTotal] = Accept;
EventTotal++;
printf("Socket %d connected/n", Accept);
}
// Process FD_READ notification
if (NetworkEvents.lNetworkEvents & FD_READ)
{
if (NetworkEvents.iErrorCode[FD_READ_BIT] != 0)
{
printf("FD_READ failed with error %d/n",
NetworkEvents.iErrorCode[FD_READ_BIT]);
break;
}
// Read data from the socket
recv(SocketArray[Index - WSA_WAIT_EVENT_0],
buffer, sizeof(buffer), 0);
}
// Process FD_WRITE notification
if (NetworkEvents.lNetworkEvents & FD_WRITE)
{
if (NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0)
{
printf("FD_WRITE failed with error %d/n",
NetworkEvents.iErrorCode[FD_WRITE_BIT]);
break;
}
send(SocketArray[Index - WSA_WAIT_EVENT_0],
buffer, sizeof(buffer), 0);
}
if (NetworkEvents.lNetworkEvents & FD_CLOSE)
{
if (NetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0)
{
printf("FD_CLOSE failed with error %d/n",
NetworkEvents.iErrorCode[FD_CLOSE_BIT]);
break;
}
closesocket(SocketArray[Index]);
// Remove socket and associated event from
// the Socket and Event arrays and decrement
// EventTotal
CompressArrays(EventArray, SocketArray, &EventTotal);
}
}
}
}
其实上例中的for循环可以不存在,只不过如果那样的话,如果第一个socket一直有event发生的话,那么数组中后边的socket总是很不到机会.
The WSAEventSelect
model offers several
advantages. It is conceptually simple and it does not require a windowed
environment. The only drawback is its limitation of waiting on only 64 events at
a time, which necessitates managing a thread pool when dealing with many
sockets. Also, because many threads are required to handle a large number of
socket connections, this model does not scale as well as the overlapped models
其实这几个模型看过以后,只要经常的回来看看这几个示例代码就可以了.
线程池技术?
The Overlapped Model:
The overlapped I/O model in Winsock offers applications better system
performance than any of the I/O models explained so far.
The overlapped model's basic design allows your application to post one or more
asynchronous I/O requests at a time using an overlapped data structure.
At a later point, the application can service the submitted requests after they
have completed. This model is available on all Windows platforms except Windows
CE. The model's overall design is based on the Windows overlapped I/O mechanisms
available for performing I/O operations on devices using the ReadFile
and WriteFile
functions.
To use the overlapped I/O model on a socket, you must first create a socket that
has the overlapped flag set.
After you successfully create a socket and bind it to a local
interface, overlapped I/O operations can commence by calling the Winsock
functions listed below and specifying an optional WSAOVERLAPPED
structure.
WSASend
WSASendTo
WSARecv
WSARecvFrom
WSAIoctl
WSARecvMsg
AcceptEx
ConnectEx
TransmitFile
TransmitPackets
DisconnectEx
WSANSPIoctl
To use overlapped I/O, each function takes a WSAOVERLAPPED
structure as a parameter.
When these functions are called with a WSAOVERLAPPED
structure, they complete
immediately—regardless of the socket's mode.
They rely on the WSAOVERLAPPED
structure to
manage the completion of an I/O request.
There are essentially two methods for managing the completion of an overlapped
I/O request: your application can wait for event object
notification
or it can process completed requests through completion routines
.
The first six functions in the list have another parameter in common: a WSAOVERLAPPED_COMPLETION_ROUTINE
. This parameter is
an optional pointer to a completion routine function that gets called when an
overlapped request completes.
Event Notification
The event notification method of overlapped I/O requires associating Windows
event objects with WSAOVERLAPPED
structures.
When I/O calls such as WSASend
and WSARecv
are made using a WSAOVERLAPPED
structure, they return immediately.
Typically, you will find that these I/O calls fail with the return value SOCKET_ERROR
and that WSAGetLastError
reports a WSA_IO_PENDING
error status.
This error status simply means that the I/O operation is in progress.
At a later time, your application will need to determine when an overlapped I/O
request completes by waiting on the event object associated with the WSAOVERLAPPED
structure.
The WSAOVERLAPPED
structure provides the
communication medium between the initiation of an overlapped I/O request and its
subsequent completion, and is defined as
typedef struct WSAOVERLAPPED
{
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
WSAEVENT hEvent;
} WSAOVERLAPPED, FAR * LPWSAOVERLAPPED;
The Internal, InternalHigh,
Offset
, and OffsetHigh
fields are all
used internally by the system and an application should not manipulate or
directly use them. The hEvent
field, on the other hand, allows an
application to associate an event object handle with this operation.
When an overlapped I/O request finally completes, your application is
responsible for retrieving the overlapped results. In the event notification method, Winsock will change the event-signaling state
of an event object that is associated with a WSAOVERLAPPED
structure from non-signaled to
signaled when an overlapped request finally completes. Because an event object is assigned to the WSAOVERLAPPED
structure, you can easily determine
when an overlapped I/O call completes by calling the WSAWaitForMultipleEvents
function
Once you determine which overlapped request has completed, you need to determine
the success or failure of the overlapped call by calling WSAGetOverlappedResult
, which is defined as
BOOL WSAGetOverlappedResult(
SOCKET s,
LPWSAOVERLAPPED lpOverlapped,
LPDWORD lpcbTransfer,
BOOL fWait,
LPDWORD lpdwFlags
);
The s
parameter
identifies the socket that was specified when the overlapped operation was
started.
The lpOverlapped
parameter is a pointer to the
WSAOVERLAPPED
structure that was specified
when the overlapped operation was started.
The lpcbTransfer
parameter is a pointer to a
DWORD
variable that receives the number of
bytes that were actually transferred by an overlapped send or receive operation.
The fWait
parameter determines whether the
function should wait for a pending overlapped operation to complete.
If fWait
is TRUE
, the function does not return until the
operation has been completed. If fWait
is
FALSE
and the operation is still pending,
WSAGetOverlappedResult
returns FALSE
with the error WSA_IO_INCOMPLETE
.Because in our case we waited on a signaled event for overlapped completion,
this parameter has no effect(这个参数在其它的情况下有用,但是在我们这个model里用不上,因).
the completion port model:
真面目
做个比喻:
socket mode:
socket s, s有两种类型,一个是blocking的,一个是non-blocking的。 如果是个人的话,那么这个人有两种, 一种是很执着的人(blocking),你派他去菜市场买菜,没卖菜的他就坐那等,一直等到买到菜。但是家里要做饭,都得等着他。另一种是会变通的人(non-blocking), 他去看到没有菜卖就会马上回家来,如果你想再让他买,就再让他去,一直到买到为止。
socket I/O models:
比如你是个大家庭,有很多人,即你有很多个socket. 你需要一个方法来管理这些s.
1 blocking + 多线程
你把这些S都设置成blocking mode的,每个S都用一个线程管理。
2 使用select模型:
如何写一个高性能的可应对多个连接的c/s程序:
The only I/O model that provides true scalability on Windows NT platforms is overlapped I/O using completion ports for notification
. In Chapter 5, we covered the various methods of socket I/O and explained that for a large number of connections, completion ports offer the greatest flexibility and ease of implementation. Mechanisms like WSAAsyncSelect
and select
are provided for easier porting from Windows 3.1 and UNIX, respectively, but are not designed to scale. The event-based models are not scalable because of the operating system limit of simultaneous wait events.
一个服务器可以接收多少个并发连接?
同一个进程中能有两个bind到同一个数据的socket吗.
什么是集群技术?
难以理解的知识点
:
一:
int ClientAddrLen = sizeof(SOCKADDR_IN);
.........
.........
..........
if ((NewConnection = accept(ListeningSocket, (SOCKADDR *) &ClientAddr,&ClientAddrLen)) == INVALID_SOCKET)
{
printf("accept failed with error %d/n", WSAGetLastError());//WSAEFault
closesocket(ListeningSocket);
WSACleanup();
return;
}
如果把第一行改为: int ClientAddrLen = sizeof(SOCKADDR_IN);
则accept()函数会一直返回invalid_socket. 并且调用WSAGetlastError()会返回0.一直不知道这个0是什么意思. 在网上看到其它人说他们的值是10014.
二
什么是spi?比如wsprecv(). 他们是比winsock API更底层一些的 service provider interface提供的,普通的api, 如send,由ws2_32.dll中来,
而spi api, 如wsprecv,则由mswsock.dll中来.
WINDOWS下的防火墙技术都被研究得比较透了
目前认为比较完善的方法就是NDIS
简单一点的就是SPI
我本来想在毕业的时候做毕业设计做个SPI防火墙,现在觉得技术难度有点低了,准备到时候做个NDIS的,完善一点的
SPI的基本原理其实和NDIS都差不多,主要体现一个思想:分层!
其实仔细想想,整个WINDOWS偶觉得都是分层式结构,假如我们用MFC写程序
那么MFC调用API,API又调用更低级的API,然后转换成相应的IRQ到内核里的驱动。。。。。
上面的话题扯得比较远了,平时我们调用WINSOCK API是这样的
winsock api->SPI->驱动->网卡
其中SPI可以由很多层构成,我们也可以插入自己的层,只要符合层与层之间的接口就行了,这个接口就是WSPStarup函数,SPI的每一层都需要为上一层提供WSPStarup函数传递自己的30个SPI函数的指针,同时调用下一层的WSPStarup函数来得到下一层SPI的30个函数指针,如果你不需要做任何事,只想中转一下,那么就可以直接在自己的函数里调用下一层SPI的相应函数提供给上一层SPI,如果想实现防火墙功能,你就在这些函数里实现自己的网络封包。
你自己写的SPI是一个DLL,也有DllMain函数,你要在DLL里把自己的WSPStartup函数导出以便上一层SPI程序调用,主要注意这个函数的最后一个参数,在WSPStartup里把你得到的下一层SPI函数指针指向你自己实现的函数就可以了
比如
int WSPStartup (
WORD wVersionRequested,
LPWSPDATAW lpWSPData,
LPWSAPROTOCOL_INFOW lpProtocolInfo,
WSPUPCALLTABLE UpcallTable,
LPWSPPROC_TABLE lpProcTable
{
.............
lpProcTable->lpWSPBind=WSPBind(....);//这样就把下一层SPI函数指针指向了自己的的WSPBind函数
}
上面就当最近一段时间研究SPI防火墙的一点总结
个人看法,分层结构是个很不错的构思,TCP/IP协议也是分层的,分层结构可以不要关注别的层之间的细节,只要专注于自己层然后按照规定提供相应的上下接口就OK了,值得我们自己在程序中借鉴!很多时候,思想更重要
相关文章推荐
- Network Programming for Microsoft Windows 2nd(Windows 网络编程第二版) 学习心得
- Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1 (ISO)
- Debugging Applications for Microsoft .NET and Microsoft Windows: Notes-The Debugging Process
- Network Programming For Microsoft Windows Notes:Winsock I/O
- Programming Visual Basic 2008: Build .NET 3.5 Applications with Microsoft's RAD Tool for Business
- Debugging Applications for Microsoft .NET and Microsoft Windows: Notes-Prerequisites to Debugging
- The Windows SDK team is proud to announce that the RTM release of the Microsoft Windows SDK for Windows Server 2008 and .NET Fra
- 翻译《Programming Microsoft Windows CE .NET, Third Edition》
- 《Premier.Press.Microsoft.Windows.Shell.Script.Programming.for.the.Absolute.Beginner》
- multicast(一) (转自network programming for microsoft windows, second edition.)
- Network Programming for Microsoft Windows 2nd Edition
- Debugging Applications for Microsoft .NET and Microsoft Windows
- 下一版本Windows® CE 开发工具Smart Device Extensions for Microsoft Visual Studio® .NET
- Debugging Applications for Microsoft .NET and Microsoft Windows: Notes-Books
- Programming Applications for Microsoft Windows核心编程(-)
- Lockless Programming Considerations for Xbox 360 and Microsoft Windows
- 下一版本Windows&reg; CE 开发工具Smart Device Extensions for Microsoft Visual Studio&reg; .NET
- Network Programming For Microsoft Windows Notes:Introduction to Winsock
- Programming Microsoft Windows Ce .Net, Third Edition(内置源码)
- Programming Applications for Microsoft Windows(二)