1.1.同步操作模式
如果当前使用的是面向连接的协议(如 TCP),则服务器可以使用Listen方法侦听连接。Accept方法处理任何传入的连接请求,并返回可用于与远程主机进行数据通信的Socket。可以使用此返回的Socket来调用Send或Receive方法。如果要指定本地 IP 地址和端口号,请在调用Listen方法之前先调用Bind方法。如果您希望基础服务提供程序为您分配可用端口,请使用端口号 0。如果希望连接到侦听主机,请调用Connect方法。若要进行数据通信,请调用Send或Receive方法。
如果当前使用的是无连接协议(如 UDP),则根本不需要侦听连接。调用ReceiveFrom方法可接受任何传入的数据报。使用SendTo方法可将数据报发送到远程主机。
1.1.1Accept方法处理任何传入的连接请求(服务端)
Socket socket =new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 创建socket对象
IPAddress hostIP = (Dns.Resolve(IPAddress.Any.ToString())).AddressList[0];// 获取主机IP
IPEndPoint ep =new IPEndPoint(hostIP, port);
listenSocket.Bind(ep);
// start listening
listenSocket.Listen(0);
Socket serverSocket =socket.Accept();//等待客户端连接,阻塞等待;
byte[] recByte =newbyte[4096];
int bytes = serverSocket.Receive(recByte, recByte.Length,0);//读取数据
string sendStr ="send to client :hello";
byte[] sendByte =Encoding.ASCII.GetBytes(sendStr);
serverSocket.Send(sendByte, sendByte.Length,0);//发送数据
serverSocket.Close();
socket.Close();
(TCP客户端)相对简单
如果希望连接到侦听主机,请调用Connect方法。若要进行数据通信,请调用Send或Receive方法。
Socket clientSocket=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 创建socket对象
IPEndPoint ep =new IPEndPoint(serverIP, port);
clientSocket.Connect(ep);
//发信息
sendStr ="send to server : hello,ni hao";
byte[] sendBytes =Encoding.ASCII.GetBytes(sendStr);
clientSocket.Send(sendBytes);//调用Send
//接收信息
byte[] recBytes =newbyte[4096];
int bytes = clientSocket.Receive(recBytes, recBytes.Length,0);//调用Receive
clientSocket.Close();//关闭连接
1.2. 异步操作模式
如果当前使用的是面向连接的协议(如 TCP),则可使用Socket、BeginConnect和EndConnect方法来连接侦听主机。通过使用BeginSend和EndSend方法,或者使用BeginReceive和EndReceive方法,可以进行异步数据通信。可以使用BeginAccept和EndAccept处理传入的连接请求。
如果您使用的是 UDP 等无连接协议,则可以使用BeginSendTo和EndSendTo来发送数据报,而使用BeginReceiveFrom和EndReceiveFrom来接收数据报。
1.2.1 BeginAccept和EndAccept处理传入的连接请求
//启动监听的线程
ListenThread = new Thread(ServerListenThread);
ListenThread.Name = "ListenThread";
ListenThread.IsBackground = true; //后台运行
ListenThread.Start();
//后台的监听线程
//通过将布尔值传递给构造函数来控制ManualResetEvent的初始状态,如果初始状态处于终止状态,为true;否则为false。
private ManualResetEvent ServerAcceptDone = new ManualResetEvent(false); //非终止状态,遇到WaitOne阻塞//也可以考虑使用EventWaitHandle
//终止状态时WaitOne()允许线程访问下边的语句
//非终止状态时WaitOne()阻塞线程,不允许线程访问下边的语句
private void ServerListenThread()
{
while (true)
{
//把非终止状态改为终止状态用Set()方法
//把终止状态改为非终止状态用Reset()方法,此时线程进入ManualEnent,调用WaitOne()将此线程阻止;
ServerAcceptDone.Reset();//重启异步连接
ServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), ServerSocket);
ServerAcceptDone.WaitOne(); //等待接受客户端
}
}
public static void AcceptCallback(IAsyncResult ar)
{
//接受回调方法。该方法的此节向主应用程序线程发出信号,让它继续处理并建立与客户端的连接
ServerAcceptDone.Set();//将信号设为终止,监听线程继续执行等待新的连接;
//获取客户端请求句柄
Socket listener = (Socket)ar.AsyncState;//
Socket handler = listener.EndAccept(ar);//完成对BeginAccept的调用 获取当前客户端
ServerStateObject state =new ServerStateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, state.BUFFER_SIZE, 0,new AsyncCallback(ReadCallback),state);//开始从连接的Socket中异步接收数据。
}
1.2.2 BeginReceive和EndReceive 接收连接的数据
public class ServerStateObject //MSDN自定义的类,用于Socket通信
{
public Socket workSocket = null;
public const int BUFFER_SIZE = 1024 * 4;
public byte[] buffer = new byte[BUFFER_SIZE];
}
//与接受回调方法一样,读取回调方法也是一个AsyncCallback委托。该方法将来自客户端套接字的一个或多个字节读入数据缓冲区,然后再次调用BeginReceive方法,直到客户端发送的数据完成为止。从客户端读取整个消息后,在控制台上显示字符串,并关闭处理与客户端的连接的服务器套接字。
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
//创建自定义的状态对象
ServerStateObject state = (ServerStateObject)ar.AsyncState;
Socket handler = state.workSocket;//处理的句柄
//读出
int bytesRead = handler.EndReceive(ar);//结束挂起的异步读取。
if(bytesRead>0)
{
String len = Encoding.UTF8.GetBytes(result).Length.ToString().PadLeft(8,’0′);
String result=Encoding.ASCII.GetString(state.buffer,0,bytesRead);
Send(len + result, handler);
}
};
state.buffer,0,bytesRead)
1.2.3 BeginSend和EndSend发送数据
private static void Send(string data, Socket handler)
{
byte[] byteData = Encoding.UTF8.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);//将数据异步发送到连接的Socket。
}
private static void SendCallback(IAsyncResult ar)
{
Socket handler = (Socket)ar.AsyncState;
//向远端发送数据
int bytesSent = handler.EndSend(ar);//结束挂起的异步发送。
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback),state);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
public static void StopListening()
{
ServerAcceptDone.Close();
}
TCP客户端异步连接、接收数据、发送数据
BeginConnect:开始一个对远程主机连接的异步请求。主机由主机名和端口号指定。
EndConnect:结束挂起的异步连接请求。
IPEndPoint RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ClientSocket.BeginConnect(RemoteEndPoint, new AsyncCallback(AsyConnectServerCallback), ClientSocket);//启动连接
//客户端 异步连接回调函数
private void AsyConnectServerCallback(IAsyncResult ar)
{
Socket ClientSocket = (Socket)ar.AsyncState;
string ErrorInfo;
try
{
ClientSocket.EndConnect(ar);
ClientConnectedFlag = true;
}
catch (SocketException ex){
ClientConnectedFlag = false;
switch (ex.ErrorCode)
{
ClientConnectedFlag = false;
switch (ex.ErrorCode)
{
case 10060://连接超时
case 10061://由于目标机器积极拒绝,无法连接
break;
default:
ErrorInfo = "AsyConnectServerCallback:" + ex.ToString();
DebugOutput.ProcessMessage(ErrorInfo);//输出到文件
break;
}
}
//向BLL层推送连接处理信息
if (ServerConnectedEvent != null)
ServerConnectedEvent(ClientSocket, ClientConnectedFlag);
if (ClientConnectedFlag == true)
ClientReceiveData(); //开始异步接受数据,此处会阻塞
}
//客户端 异步接收数据回调函数
private void ClientReceiveDataCallback(IAsyncResult ar)
{
string ErrorInfo;
try
{
if (ClientConnectedFlag == true)
{
ClientStateObject ClientReceiveState = (ClientStateObject)ar.AsyncState;
Socket TempReceiveSocket = ClientReceiveState.workSocket;
if (TempReceiveSocket != null && TempReceiveSocket.Connected)
{
int ClientReceiveDataSize = TempReceiveSocket.EndReceive(ar);
if (ClientReceiveDataSize > 0)
{
if (ClientRecStrEvent != null)
{
ClientRecStrEvent(TempReceiveSocket, ClientReceiveState.buffer, ClientReceiveDataSize);//推送到上一层。
}
ClientReciveDone.Set();
TempReceiveSocket.BeginReceive(ClientReceiveState.buffer, 0, ClientStateObject.BUFFER_SIZE, 0, new AsyncCallback(ClientReceiveDataCallback), ClientReceiveState);
ClientReciveDone.WaitOne();
}
else
{//远程服务器关闭通知
CloseClient();//关闭连接
//向BLL层推送连接处理信息
if (ServerConnectedEvent != null)
ServerConnectedEvent(ClientSocket, ClientConnectedFlag);
}
}
}
}
catch (SocketException ex)
{
ErrorInfo = String.Format("ClientReceiveDataCallback:[{0}] {1}", ex.ErrorCode, ex.ToString());
DebugOutput.ProcessMessage(ErrorInfo);//输出到文件
if (ex.ErrorCode == 10054)
{
CloseClient();//关闭连接
//向BLL层推送连接处理信息
if (ServerConnectedEvent != null)
ServerConnectedEvent(ClientSocket, ClientConnectedFlag);
}
}
}
详情参考:https://msdn.microsoft.com/zh-cn/library/6y0e13d3(v=vs.80).aspx