网络编程序列2——C#TCP服务端代码实现二




1.1.同步操作模式

如果当前使用的是面向连接的协议(如 TCP),则服务器可以使用Listen方法侦听连接。Accept方法处理任何传入的连接请求,并返回可用于与远程主机进行数据通信的Socket。可以使用此返回的Socket来调用SendReceive方法。如果要指定本地 IP 地址和端口号,请在调用Listen方法之前先调用Bind方法。如果您希望基础服务提供程序为您分配可用端口,请使用端口号 0。如果希望连接到侦听主机,请调用Connect方法。若要进行数据通信,请调用SendReceive方法。

如果当前使用的是无连接协议(如 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方法。若要进行数据通信,请调用SendReceive方法。

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),则可使用SocketBeginConnectEndConnect方法来连接侦听主机。通过使用BeginSendEndSend方法,或者使用BeginReceiveEndReceive方法,可以进行异步数据通信。可以使用BeginAcceptEndAccept处理传入的连接请求。

如果您使用的是 UDP 等无连接协议,则可以使用BeginSendToEndSendTo来发送数据报,而使用BeginReceiveFromEndReceiveFrom来接收数据报。

1.2.1 BeginAcceptEndAccept处理传入的连接请求



//启动监听的线程

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 BeginReceiveEndReceive 接收连接的数据

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 BeginSendEndSend发送数据

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值