最近浏览了几篇有关Socket发送消息的文章,发现大家对Socket Send方法理解有所偏差,现将自己在开发过程中对Socket的领悟写出来,以供大家参考。

  (一)架构

  基于TCP协议的Socket通信,架构类似于B/S架构,一个Socket通信服务器,多个Socket通信客户端。Socket通信服务器启动时,会建立一个侦听Socket,侦听Socket将侦听到的Socket连接传给接受Socket,然后由接受Socket完成接受、发送消息,当Socket存在异常时,断开连接。在实际开发项目中,往往要求Socket通信服务器能提供高效、稳定的服务,一般会用到以下技术:双工通信、完成端口、SAEA、池、多线程、异步等。特别是池,用的比较多,池一般包括一下几种:

1)Buffer池,用于集中管控Socket缓冲区,防止内存碎片。

2)SAEA池,用于集中管控Socket,重复利用Socket。

3)SQL池,用于分离网络服务层与数据访问层(SQL的执行效率远远低于网络层执行效率)。

4)线程池,用于从线程池中调用空闲线程执行业务逻辑,进一步提高网络层运行效率。

  (二)Send

  主服务器接受Socket为一端口,客户端Socket为一端口,这两个端口通过TCP协议建立连接,通信基础系统负责管理此连接,它有两个功能:

  1)发送消息

  2)接受消息

  Socket的Send方法,并非大家想象中的从一个端口发送消息到另一个端口,它仅仅是拷贝数据到基础系统的发送缓冲区,然后由基础系统将发送缓冲区的数据到连接的另一端口。值得一说的是,这里的拷贝数据与异步发送消息的拷贝是不一样的,同步发送的拷贝,是直接拷贝数据到基础系统缓冲区,拷贝完成后返回,在拷贝的过程中,执行线程会IO等待, 此种拷贝与Socket自带的Buffer空间无关,但异步发送消息的拷贝,是将Socket自带的Buffer空间内的所有数据,拷贝到基础系统发送缓冲区,并立即返回,执行线程无需IO等待,所以异步发送在发送前必须执行SetBuffer方法,拷贝完成后,会触发你自定义回调函数ProcessSend,在ProcessSend方法中,调用SetBuffer方法,重新初始化Buffer空间。

  口说无凭,下面给个例子:

  服务器端:

客户端:

解释:

客户端第一次发送数据:1234567890。

客户端第一个接受数据:1234567890,该数据由服务端用Send同步方法发送返回。

客户端第二个接受数据:1234567890,该数据由服务端用Send异步方法发送返回。

以上似乎没什么异常,好,接下来,我只发送abc。

客户端第一个接受数据:abc,理所当然,没什么问题。

客户端第二个接受数据:abc4567890!为什么呢?应该是abc才对呀!

好,现在为大家解释一下:

异步发送是将其Buffer空间中所有数据拷贝到基础系统发送缓冲区,第一次拷贝1234567890到发送缓冲区,所以收到1234567890,第二次拷贝abc到发送缓冲区,替换了先前的123,所以收到abc4567890,大家明白的?

源码:

BufferManager
using System.Collections.Generic;
using System.Net.Sockets;
// This class creates a single large buffer which can be divided up
// and assigned to SocketAsyncEventArgs objects for use with each
// socket I/O operation.
// This enables bufffers to be easily reused and guards against
// fragmenting heap memory.
//
// The operations exposed on the BufferManager class are not thread safe.
class BufferManager
{
int m_numBytes; // the total number of bytes controlled by the buffer pool
byte[] m_buffer; // the underlying byte array maintained by the Buffer Manager
Stack<int> m_freeIndexPool; //
int m_currentIndex;
int m_bufferSize;
public BufferManager(int totalBytes, int bufferSize)
{
m_numBytes = totalBytes;
m_currentIndex =0;
m_bufferSize = bufferSize;
m_freeIndexPool =new Stack<int>();
}
// Allocates buffer space used by the buffer pool
publicvoid InitBuffer()
{
// create one big large buffer and divide that
// out to each SocketAsyncEventArg object
m_buffer =newbyte[m_numBytes];
}
// Assigns a buffer from the buffer pool to the
// specified SocketAsyncEventArgs object
//
// <returns>true if the buffer was successfully set, else false</returns>
publicbool SetBuffer(SocketAsyncEventArgs args)
{
if (m_freeIndexPool.Count >0)
{
args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize);
}
else
{
if ((m_numBytes - m_bufferSize) < m_currentIndex)
{
returnfalse;
}
args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize);
m_currentIndex += m_bufferSize;
}
returntrue;
}
// Removes the buffer from a SocketAsyncEventArg object.
// This frees the buffer back to the buffer pool
publicvoid FreeBuffer(SocketAsyncEventArgs args)
{
m_freeIndexPool.Push(args.Offset);
args.SetBuffer(null, 0, 0);
}
}
SocketAsyncEventArgsPool
using System;
using System.Collections.Generic;
using System.Net.Sockets;
// Represents a collection of reusable SocketAsyncEventArgs objects.
class SocketAsyncEventArgsPool
{
Stack<SocketAsyncEventArgs> m_pool;
// Initializes the object pool to the specified size
//
// The "capacity" parameter is the maximum number of
// SocketAsyncEventArgs objects the pool can hold
public SocketAsyncEventArgsPool(int capacity)
{
m_pool =new Stack<SocketAsyncEventArgs>(capacity);
}
// Add a SocketAsyncEventArg instance to the pool
//
//The "item" parameter is the SocketAsyncEventArgs instance
// to add to the pool
publicvoid Push(SocketAsyncEventArgs item)
{
if (item ==null) { thrownew ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); }
lock (m_pool)
{
m_pool.Push(item);
}
}
// Removes a SocketAsyncEventArgs instance from the pool
// and returns the object removed from the pool
public SocketAsyncEventArgs Pop()
{
lock (m_pool)
{
return m_pool.Pop();
}
}
// The number of SocketAsyncEventArgs instances in the pool
publicint Count
{
get { return m_pool.Count; }
}
} using System;
using System.Collections.Generic;
using System.Net.Sockets; // Represents a collection of reusable SocketAsyncEventArgs objects. 
class SocketAsyncEventArgsPool
{
Stack<SocketAsyncEventArgs> m_pool; // Initializes the object pool to the specified size
//
// The "capacity" parameter is the maximum number of 
// SocketAsyncEventArgs objects the pool can hold
public SocketAsyncEventArgsPool(int capacity)
{
m_pool =new Stack<SocketAsyncEventArgs>(capacity);
} // Add a SocketAsyncEventArg instance to the pool
//
//The "item" parameter is the SocketAsyncEventArgs instance 
// to add to the pool
publicvoid Push(SocketAsyncEventArgs item)
{
if (item ==null) { thrownew ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); }
lock (m_pool)
{
m_pool.Push(item);
}
} // Removes a SocketAsyncEventArgs instance from the pool
// and returns the object removed from the pool
public SocketAsyncEventArgs Pop()
{
lock (m_pool)
{
return m_pool.Pop();
}
} // The number of SocketAsyncEventArgs instances in the pool
publicint Count
{
get { return m_pool.Count; }
} }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets; class AsyncUserToken
{
public Socket Socket;
}
Server
using System;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Text;
// 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
{
privateint m_numConnections; // the maximum number of connections the sample is designed to handle simultaneously
privateint 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
constint 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.
//
publicvoid 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>
publicvoid 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>
publicvoid 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);
}
privatevoid 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:
thrownew 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.
//
privatevoid 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); Int32 BytesToProcess = e.BytesTransferred;
Byte[] bt =new Byte[BytesToProcess];
Buffer.BlockCopy(e.Buffer, e.Offset, bt, 0, BytesToProcess);
string strReceive = Encoding.Default.GetString(bt); Send(token.Socket, bt, 0, bt.Length, 1000); Thread.Sleep(1000);
//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);
}
} publicstaticvoid Send(Socket socket, byte[] buffer, int offset, int size, int timeout)
{
socket.SendTimeout =0;
int startTickCount = Environment.TickCount;
int sent =0; // how many bytes is already sent
do
{
if (Environment.TickCount > startTickCount + timeout)
//throw new Exception("Timeout.");
try
{
sent += socket.Send(buffer, offset + sent, size - sent, SocketFlags.None);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably full, wait and try again
Thread.Sleep(30);
}
else
throw ex; // any serious error occurr
}
} while (sent < size);
}
 
// 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>
privatevoid ProcessSend(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
//e.SetBuffer(e.Offset, 10);
// 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);
}
}
privatevoid 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);
}
} using System;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Text; // 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
{
privateint m_numConnections; // the maximum number of connections the sample is designed to handle simultaneously 
privateint 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
constint 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.
//
publicvoid 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>
publicvoid 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>
publicvoid 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);
} privatevoid 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:
thrownew 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.
//
privatevoid 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); Int32 BytesToProcess = e.BytesTransferred;
Byte[] bt =new Byte[BytesToProcess];
Buffer.BlockCopy(e.Buffer, e.Offset, bt, 0, BytesToProcess);
string strReceive = Encoding.Default.GetString(bt); Send(token.Socket, bt, 0, bt.Length, 1000); Thread.Sleep(1000); //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);
}
} publicstaticvoid Send(Socket socket, byte[] buffer, int offset, int size, int timeout)
{
socket.SendTimeout =0;
int startTickCount = Environment.TickCount;
int sent =0; // how many bytes is already sent
do
{
if (Environment.TickCount > startTickCount + timeout)
//throw new Exception("Timeout.");
try
{
sent += socket.Send(buffer, offset + sent, size - sent, SocketFlags.None);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably full, wait and try again
Thread.Sleep(30);
}
else
throw ex; // any serious error occurr
}
} while (sent < size);
} // 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>
privatevoid ProcessSend(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
//e.SetBuffer(e.Offset, 10); // 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);
}
} privatevoid 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);
} }
Program
using System;
using System.Net;
using System.Collections.Generic;
using System.IO;
class Program
{
staticvoid Main(string[] args)
{
IPEndPoint iep =new IPEndPoint(IPAddress.Parse("10.1.20.6"), 1333);
Server objServer =new Server(1000, 10);
objServer.Init();
objServer.Start(iep);
}
} using System;
using System.Net;
using System.Collections.Generic;
using System.IO; class Program
{
staticvoid Main(string[] args)
{
IPEndPoint iep =new IPEndPoint(IPAddress.Parse("10.1.20.6"), 1333); Server objServer =new Server(1000, 10);
objServer.Init();
objServer.Start(iep);
}
}

转:socket的更多相关文章

  1. socket读写返回值的处理

    在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...

  2. Socket聊天程序——Common

    写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...

  3. Socket聊天程序——客户端

    写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...

  4. Socket聊天程序——服务端

    写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...

  5. Socket聊天程序——初始设计

    写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...

  6. Java中的Socket的用法

                                   Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...

  7. Android Socket连接PC出错问题及解决

    最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.

  8. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  9. Mono 3.2.3 Socket功能迎来一稳定的版本

    由于兴趣自己业余时间一直在搞.net下面的通讯应用,mono的存在得以让.NET程序轻松运行在Linux之下.不过经过多尝试Socket相关功能在Mono下的表现并不理想.不管性能还是吞吐能力方面离我 ...

  10. Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!

    随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...

随机推荐

  1. 11 - JavaSE之GUI

    GUI(念法 gu yi) AWT AWT(Abstract Window Toolkit 抽象窗口开发包,在C# 或者 linux窗口开发类之上又封装一层,达到跨平台的目的)包括了很多类和接口,用于 ...

  2. Java虚拟机(二):JVM内存模型

    所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问 ...

  3. T-SQL 片段收藏

    存储过程 CREATE PROCEDURE spInsertOrUpdateProduct --有则更新,否则插入 ) , ) , @StdCost MONEY AS IF EXISTS ( SELE ...

  4. HTML自己整理

    1.margin:0 auto 表示什么意思?? margin后面如果只有两个参数的话,第一个表示top和bottom,第二个表示left和right因为0 auto,表示上下边界为0,左右则根据宽度 ...

  5. java.text包

    JDK在java.text包中,提供了对显示对象格式化的接口.类及异常处理,这里我们只来谈一谈text包中的format类及其子类.其中,最重要的是两个差不多互为“逆运算”的方法format(将某对象 ...

  6. CSS选择器详解(一)常用选择器

    目录 类型选择器 类选择器 ID选择器 伪类 伪元素 类型选择器 通过类型选择器可以选择某一类型的html标签,并对其使用样式. 语法: selector {property1: value; pro ...

  7. redis实战笔记(7)-第7章 基于搜索的应用程序

    本章主要内容   使用Redis进行搜索 对搜索结果进行排序 实现广告定向 实现职位搜索    

  8. rails安全性

    如果你发布你的blog.那么其他人就可以随便修改和添加博客了. Rails提供了一个非常简单的http认证系统,可以非常有帮助的解决这种情况. 在PostsController里面我们需要一个方法阻止 ...

  9. [codeup] 1128 出租车费

    题目描述 某市出租车计价规则如下:起步4公里10元,即使你的行程没超过4公里:接下来的4公里,每公里2元:之后每公里2.4元.行程的最后一段即使不到1公里,也当作1公里计费. 一个乘客可以根据行程公里 ...

  10. Spring系列之——Spring事务以及两大核心IOC和AOP

    1 Spring事务 1.1 Spring事务是什么(百度) 事务是对一系列的数据库操作(比如插入多条数据)进行统一的提交或是回滚操作,如果插入成功,那么一起成功,如果中间一条出现异常,那么回滚之前的 ...