这个类比较混乱,完全有道理不用它。使用比较简洁的Accept、Receive(或者BeginAccept、BeginReceive)就行了。
解决方案 »
- 有关违章查询的问题!
- 在VS中建的网站,调试运行能成功,为什么在IIS中不行?
- 有问题
- C# webBrowser1 问题
- 有没有用Win2000系统的朋友,帮个忙调试一下.在线等待.
- 关于uml的泳道问题
- 有关 winform datagrid GotFocus 事件无效果的问题
- [WinForm问题]请问各位,关于DataGrid中添加CheckBox列的问题,谢谢
- 本人有串口发送短信的完整程序
- 例子程序问题:Update Application Block例子SelfUpdating出错,请帮忙看看??
- visual studio 2010解决方案提示项目被卸载
- 关于反射获取带out参数的静态方法问题
msdn上有一个很好的例子。可以拿过来直接用。
// Implements the connection logic for the socket server.
// After accepting a connection, all data read from the client
// is sent back to the client. The read and echo back to the client pattern
// is continued until the client disconnects.
class Server
{
private int m_numConnections; // the maximum number of connections the sample is designed to handle simultaneously
private int m_receiveBufferSize;// buffer size to use for each socket I/O operation
BufferManager m_bufferManager; // represents a large reusable set of buffers for all socket operations
const int opsToPreAlloc = 2; // read, write (don't alloc buffer space for accepts)
Socket listenSocket; // the socket used to listen for incoming connection requests
// pool of reusable SocketAsyncEventArgs objects for write, read and accept socket operations
SocketAsyncEventArgsPool m_readWritePool;
int m_totalBytesRead; // counter of the total # bytes received by the server
int m_numConnectedSockets; // the total number of clients connected to the server
Semaphore m_maxNumberAcceptedClients; // Create an uninitialized server instance.
// To start the server listening for connection requests
// call the Init method followed by Start method
//
// <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously</param>
// <param name="receiveBufferSize">buffer size to use for each socket I/O operation</param>
public Server(int numConnections, int receiveBufferSize)
{
m_totalBytesRead = 0;
m_numConnectedSockets = 0;
m_numConnections = numConnections;
m_receiveBufferSize = receiveBufferSize;
// allocate buffers such that the maximum number of sockets can have one outstanding read and
//write posted to the socket simultaneously
m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc,
receiveBufferSize); m_readWritePool = new SocketAsyncEventArgsPool(numConnections);
m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections);
} // Initializes the server by preallocating reusable buffers and
// context objects. These objects do not need to be preallocated
// or reused, but it is done this way to illustrate how the API can
// easily be used to create reusable objects to increase server performance.
//
public void Init()
{
// Allocates one large byte buffer which all I/O operations use a piece of. This gaurds
// against memory fragmentation
m_bufferManager.InitBuffer(); // preallocate pool of SocketAsyncEventArgs objects
SocketAsyncEventArgs readWriteEventArg; for (int i = 0; i < m_numConnections; i++)
{
//Pre-allocate a set of reusable SocketAsyncEventArgs
readWriteEventArg = new SocketAsyncEventArgs();
readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
readWriteEventArg.UserToken = new AsyncUserToken(); // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
m_bufferManager.SetBuffer(readWriteEventArg); // add SocketAsyncEventArg to the pool
m_readWritePool.Push(readWriteEventArg);
} } // Starts the server such that it is listening for
// incoming connection requests.
//
// <param name="localEndPoint">The endpoint which the server will listening
// for connection requests on</param>
public void Start(IPEndPoint localEndPoint)
{
// create the socket which listens for incoming connections
listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(localEndPoint);
// start the server with a listen backlog of 100 connections
listenSocket.Listen(100); // post accepts on the listening socket
StartAccept(null); //Console.WriteLine("{0} connected sockets with one outstanding receive posted to each....press any key", m_outstandingReadCount);
Console.WriteLine("Press any key to terminate the server process....");
Console.ReadKey();
}
// Begins an operation to accept a connection request from the client
//
// <param name="acceptEventArg">The context object to use when issuing
// the accept operation on the server's listening socket</param>
public void StartAccept(SocketAsyncEventArgs acceptEventArg)
{
if (acceptEventArg == null)
{
acceptEventArg = new SocketAsyncEventArgs();
acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
}
else
{
// socket must be cleared since the context object is being reused
acceptEventArg.AcceptSocket = null;
} m_maxNumberAcceptedClients.WaitOne();
bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);
if (!willRaiseEvent)
{
ProcessAccept(acceptEventArg);
}
} // This method is the callback method associated with Socket.AcceptAsync
// operations and is invoked when an accept operation is complete
//
void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
{
ProcessAccept(e);
} private void ProcessAccept(SocketAsyncEventArgs e)
{
Interlocked.Increment(ref m_numConnectedSockets);
Console.WriteLine("Client connection accepted. There are {0} clients connected to the server",
m_numConnectedSockets); // Get the socket for the accepted client connection and put it into the
//ReadEventArg object user token
SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop();
((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket; // As soon as the client is connected, post a receive to the connection
bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
if(!willRaiseEvent){
ProcessReceive(readEventArgs);
} // Accept the next connection request
StartAccept(e);
} // This method is called whenever a receive or send operation is completed on a socket
//
// <param name="e">SocketAsyncEventArg associated with the completed receive operation</param>
void IO_Completed(object sender, SocketAsyncEventArgs e)
{
// determine which type of operation just completed and call the associated handler
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
ProcessSend(e);
break;
default:
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
} } // This method is invoked when an asynchronous receive operation completes.
// If the remote host closed the connection, then the socket is closed.
// If data was received then the data is echoed back to the client.
//
private void ProcessReceive(SocketAsyncEventArgs e)
{
// check if the remote host closed the connection
AsyncUserToken token = (AsyncUserToken)e.UserToken;
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
//increment the count of the total bytes receive by the server
Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred);
Console.WriteLine("The server has read a total of {0} bytes", m_totalBytesRead); //echo the data received back to the client
e.SetBuffer(e.Offset, e.BytesTransferred);
bool willRaiseEvent = token.Socket.SendAsync(e);
if (!willRaiseEvent)
{
ProcessSend(e);
} }
else
{
CloseClientSocket(e);
}
} // This method is invoked when an asynchronous send operation completes.
// The method issues another receive on the socket to read any additional
// data sent from the client
//
// <param name="e"></param>
private void ProcessSend(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// done echoing data back to the client
AsyncUserToken token = (AsyncUserToken)e.UserToken;
// read the next block of data send from the client
bool willRaiseEvent = token.Socket.ReceiveAsync(e);
if (!willRaiseEvent)
{
ProcessReceive(e);
}
}
else
{
CloseClientSocket(e);
}
} private void CloseClientSocket(SocketAsyncEventArgs e)
{
AsyncUserToken token = e.UserToken as AsyncUserToken; // close the socket associated with the client
try
{
token.Socket.Shutdown(SocketShutdown.Send);
}
// throws if client process has already closed
catch (Exception) { }
token.Socket.Close(); // decrement the counter keeping track of the total number of clients connected to the server
Interlocked.Decrement(ref m_numConnectedSockets);
m_maxNumberAcceptedClients.Release();
Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets); // Free the SocketAsyncEventArg so they can be reused by another client
m_readWritePool.Push(e);
}}
upupupup
upup
upup
upup
后来想用aio做,但那个通信模型实在是复杂,当时水平也不行,就不了了之了。
SocketAsyncEventArgs 和 socket 如何配合工作的??机制是什么?
跟iocp没有什么关系。.net framework的 TcpListener就是基于IOCP的。而SocketAsyncEventArgs只不过是一个参数调用类型(就好像你可以使用ado.net也可以使用ef来调用sql server一样),这个参数形式跟服务系统用不用IOCP,没有关系。
{
Separated = Encoding.UTF8.GetBytes(SeparatedText);
_Server = server;
_Port = port;
var ConnectArgs = new SocketAsyncEventArgs { RemoteEndPoint = new DnsEndPoint(this.Server, this.Port) };
ConnectArgs.Completed += ConnectArgs_Completed;
clt = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clt.ConnectAsync(ConnectArgs);
} private Socket clt; void ConnectArgs_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError != SocketError.Success)
throw new Exception("网络连接失败。请检查服务器或者网络。"); switch (e.LastOperation)
{
case SocketAsyncOperation.Connect:
e.SetBuffer(new byte[409600], 0, 409600);
clt.ReceiveAsync(e);
break;
case SocketAsyncOperation.Receive:
ProcessReceive(e);
clt.ReceiveAsync(e);
break;
}
}
private List<byte> ReadDatas = new List<byte>(); private void ProcessReceive(SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 0)
{
var len = e.BytesTransferred;
for (var i = 0; i < len; i++)
ReadDatas.Add(e.Buffer[i]);
if (ReadDatas.Count > Separated.Length && EndWithSeparated(ReadDatas.ToArray()))
{
ReadDatas.RemoveRange(ReadDatas.Count - Separated.Length, Separated.Length);
foreach (var line in Split(ReadDatas.ToArray())) //分割为多个消息
{
var ln = DecompressedAndGetString(line); //解密为字符串命令
new Thread(() => ProcessReceive(ln)).Start(); //执行客户端命令
}
ReadDatas.Clear();
}
}
}