1.1.同步操作模式
如果當(dāng)前使用的是面向連接的協(xié)議(如 TCP),則服務(wù)器可以使用Listen方法偵聽連接娶桦。Accept方法處理任何傳入的連接請(qǐng)求,并返回可用于與遠(yuǎn)程主機(jī)進(jìn)行數(shù)據(jù)通信的Socket汁汗≈云瑁可以使用此返回的Socket來調(diào)用Send或Receive方法。如果要指定本地 IP 地址和端口號(hào)知牌,請(qǐng)?jiān)谡{(diào)用Listen方法之前先調(diào)用Bind方法祈争。如果您希望基礎(chǔ)服務(wù)提供程序?yàn)槟峙淇捎枚丝冢?qǐng)使用端口號(hào) 0角寸。如果希望連接到偵聽主機(jī)菩混,請(qǐng)調(diào)用Connect方法。若要進(jìn)行數(shù)據(jù)通信扁藕,請(qǐng)調(diào)用Send或Receive方法沮峡。
如果當(dāng)前使用的是無連接協(xié)議(如 UDP),則根本不需要偵聽連接亿柑。調(diào)用ReceiveFrom方法可接受任何傳入的數(shù)據(jù)報(bào)帖烘。使用SendTo方法可將數(shù)據(jù)報(bào)發(fā)送到遠(yuǎn)程主機(jī)。
1.1.1Accept方法處理任何傳入的連接請(qǐng)求(服務(wù)端)
Socket socket =new Socket(AddressFamily.InterNetwork, SocketType.Stream,? ProtocolType.Tcp);// 創(chuàng)建socket對(duì)象
IPAddress hostIP = (Dns.Resolve(IPAddress.Any.ToString())).AddressList[0];// 獲取主機(jī)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);//讀取數(shù)據(jù)
string sendStr ="send to client :hello";
byte[] sendByte =Encoding.ASCII.GetBytes(sendStr);
serverSocket.Send(sendByte, sendByte.Length,0);//發(fā)送數(shù)據(jù)
serverSocket.Close();
socket.Close();
(TCP客戶端)相對(duì)簡(jiǎn)單
如果希望連接到偵聽主機(jī),請(qǐng)調(diào)用Connect方法式矫。若要進(jìn)行數(shù)據(jù)通信乡摹,請(qǐng)調(diào)用Send或Receive方法。
Socket clientSocket=new Socket(AddressFamily.InterNetwork, SocketType.Stream,? ProtocolType.Tcp);// 創(chuàng)建socket對(duì)象
IPEndPoint ep =new IPEndPoint(serverIP, port);
clientSocket.Connect(ep);
//發(fā)信息
sendStr ="send to server : hello,ni hao";
byte[] sendBytes =Encoding.ASCII.GetBytes(sendStr);
clientSocket.Send(sendBytes);//調(diào)用Send
//接收信息
byte[] recBytes =newbyte[4096];
int bytes = clientSocket.Receive(recBytes, recBytes.Length,0);//調(diào)用Receive
clientSocket.Close();//關(guān)閉連接
1.2. 異步操作模式
如果當(dāng)前使用的是面向連接的協(xié)議(如 TCP)采转,則可使用Socket聪廉、BeginConnect和EndConnect方法來連接偵聽主機(jī)。通過使用BeginSend和EndSend方法故慈,或者使用BeginReceive和EndReceive方法板熊,可以進(jìn)行異步數(shù)據(jù)通信〔毂粒可以使用BeginAccept和EndAccept處理傳入的連接請(qǐng)求干签。
如果您使用的是 UDP 等無連接協(xié)議,則可以使用BeginSendTo和EndSendTo來發(fā)送數(shù)據(jù)報(bào)拆撼,而使用BeginReceiveFrom和EndReceiveFrom來接收數(shù)據(jù)報(bào)容劳。
1.2.1?BeginAccept和EndAccept處理傳入的連接請(qǐng)求
//啟動(dòng)監(jiān)聽的線程
ListenThread = new Thread(ServerListenThread);
ListenThread.Name = "ListenThread";
ListenThread.IsBackground = true;? //后臺(tái)運(yùn)行
ListenThread.Start();
//后臺(tái)的監(jiān)聽線程
//通過將布爾值傳遞給構(gòu)造函數(shù)來控制ManualResetEvent的初始狀態(tài)喘沿,如果初始狀態(tài)處于終止?fàn)顟B(tài),為true竭贩;否則為false蚜印。
private ManualResetEvent ServerAcceptDone = new ManualResetEvent(false); ? ? ?//非終止?fàn)顟B(tài),遇到WaitOne阻塞//也可以考慮使用EventWaitHandle
//終止?fàn)顟B(tài)時(shí)WaitOne()允許線程訪問下邊的語(yǔ)句
//非終止?fàn)顟B(tài)時(shí)WaitOne()阻塞線程留量,不允許線程訪問下邊的語(yǔ)句
private void ServerListenThread()
{
while (true)
{
//把非終止?fàn)顟B(tài)改為終止?fàn)顟B(tài)用Set()方法
//把終止?fàn)顟B(tài)改為非終止?fàn)顟B(tài)用Reset()方法,此時(shí)線程進(jìn)入ManualEnent,調(diào)用WaitOne()將此線程阻止窄赋;
ServerAcceptDone.Reset();//重啟異步連接
ServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), ServerSocket);
ServerAcceptDone.WaitOne();? ? ? //等待接受客戶端
}
}
public static void AcceptCallback(IAsyncResult ar)
{
//接受回調(diào)方法。該方法的此節(jié)向主應(yīng)用程序線程發(fā)出信號(hào)楼熄,讓它繼續(xù)處理并建立與客戶端的連接
ServerAcceptDone.Set();//將信號(hào)設(shè)為終止寝凌,監(jiān)聽線程繼續(xù)執(zhí)行等待新的連接;
//獲取客戶端請(qǐng)求句柄
Socket?listener?=?(Socket)ar.AsyncState;//
Socket handler = listener.EndAccept(ar);//完成對(duì)BeginAccept的調(diào)用 獲取當(dāng)前客戶端
ServerStateObject state =new ServerStateObject();
state.workSocket?=?handler;
handler.BeginReceive(state.buffer, 0, state.BUFFER_SIZE, 0,new AsyncCallback(ReadCallback),state);//開始從連接的Socket中異步接收數(shù)據(jù)孝赫。
}
1.2.2?BeginReceive和EndReceive?接收連接的數(shù)據(jù)
public class ServerStateObject? //MSDN自定義的類较木,用于Socket通信
{
public Socket workSocket = null;
public const int BUFFER_SIZE = 1024 * 4;
public byte[] buffer = new byte[BUFFER_SIZE];
}
//與接受回調(diào)方法一樣,讀取回調(diào)方法也是一個(gè)AsyncCallback委托青柄。該方法將來自客戶端套接字的一個(gè)或多個(gè)字節(jié)讀入數(shù)據(jù)緩沖區(qū)伐债,然后再次調(diào)用BeginReceive方法,直到客戶端發(fā)送的數(shù)據(jù)完成為止致开。從客戶端讀取整個(gè)消息后峰锁,在控制臺(tái)上顯示字符串,并關(guān)閉處理與客戶端的連接的服務(wù)器套接字双戳。
public static void ReadCallback(IAsyncResult?ar)
{
String?content?=?String.Empty;
//創(chuàng)建自定義的狀態(tài)對(duì)象
ServerStateObject state = (ServerStateObject)ar.AsyncState;
Socket?handler?=?state.workSocket;//處理的句柄
//讀出
int bytesRead = handler.EndReceive(ar);//結(jié)束掛起的異步讀取虹蒋。
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發(fā)送數(shù)據(jù)
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);//將數(shù)據(jù)異步發(fā)送到連接的Socket飒货。
}
private static void SendCallback(IAsyncResult ar)
{
Socket handler = (Socket)ar.AsyncState;
//向遠(yuǎn)端發(fā)送數(shù)據(jù)
int bytesSent = handler.EndSend(ar);//結(jié)束掛起的異步發(fā)送魄衅。
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客戶端異步連接、接收數(shù)據(jù)塘辅、發(fā)送數(shù)據(jù)
BeginConnect:開始一個(gè)對(duì)遠(yuǎn)程主機(jī)連接的異步請(qǐng)求晃虫。主機(jī)由主機(jī)名和端口號(hào)指定。
EndConnect:結(jié)束掛起的異步連接請(qǐng)求扣墩。
IPEndPoint RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ClientSocket.BeginConnect(RemoteEndPoint, new AsyncCallback(AsyConnectServerCallback), ClientSocket);//啟動(dòng)連接
//客戶端 異步連接回調(diào)函數(shù)
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://連接超時(shí)
case 10061://由于目標(biāo)機(jī)器積極拒絕哲银,無法連接
break;
default:
ErrorInfo = "AsyConnectServerCallback:" + ex.ToString();
DebugOutput.ProcessMessage(ErrorInfo);//輸出到文件
break;
}
}
//向BLL層推送連接處理信息
if (ServerConnectedEvent != null)
ServerConnectedEvent(ClientSocket, ClientConnectedFlag);
if (ClientConnectedFlag == true)
ClientReceiveData(); //開始異步接受數(shù)據(jù),此處會(huì)阻塞
}
//客戶端 異步接收數(shù)據(jù)回調(diào)函數(shù)
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
{//遠(yuǎn)程服務(wù)器關(guān)閉通知
CloseClient();//關(guān)閉連接
//向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();//關(guān)閉連接
//向BLL層推送連接處理信息
if (ServerConnectedEvent != null)
ServerConnectedEvent(ClientSocket, ClientConnectedFlag);
}
}
}
詳情參考:https://msdn.microsoft.com/zh-cn/library/6y0e13d3(v=vs.80).aspx