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

来源:互联网 发布:淘宝卖家购物车加购数 编辑:程序博客网 时间:2024/06/14 22:02




1.1.同步操作模式

如果当前使用的是面向连接的协议(如 TCP),则服务器可以使用Listen方法侦听连接。Accept方法处理任何传入的连接请求,并返回可用于与远程主机进行数据通信的Socket。可以使用此返回的Socket来调用Send或Receive方法。如果要指定本地 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),则可使用Socket、BeginConnect和EndConnect方法来连接侦听主机。通过使用BeginSend和EndSend方法,或者使用BeginReceiveEndReceive方法,可以进行异步数据通信。可以使用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

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 畅聊之火消失了怎么办 手机版WPS打开文档空白怎么办 空白表格怎么打印不出来怎么办 微信朋友太少怎么办 js和CSS加载失败怎么办 熹妃q传密码忘了怎么办 苹果手机淘宝占用空间大怎么办 苹果相册储存空间不足怎么办 企业网银里的收款名单丢失怎么办 发邮件发错了怎么办 qq群成员满500了怎么办 为什么qq群查不到信息怎么办 tiger杯子油漆划掉了怎么办 手被油漆弄到了怎么办 被油漆弄到衣服怎么办 QQ发表情成问号怎么办 qq登不了微信怎么办 qq不能登录微信怎么办 qq号一年没用了怎么办 微信里别人可以看到我手机号怎么办 用手机号注册的微信换号后怎么办 微信群推送名片很多人加怎么办 志高制冷显示ff怎么办 百度账号手机号换了怎么办 别人盗取手机号的通讯录该怎么办 58简历看不到真实号码怎么办 淘宝更换手机号码说已注册怎么办 系统把qq冻结了怎么办 qq被永久冻结好友怎么办 群发不小心发错怎么办 qq群成员满了怎么办 qq知道密码没手机号验证怎么办 改房本上的名字怎么办 支付宝租给别人怎么办 微信麻将房间卡怎么办 皮肤挤伤了发黑怎么办 指甲被挤了黑了怎么办 手指被挤了变黑怎么办 榆次买房太原户口怎么办 皮肤又红又黑怎么办 打仙桃晃晃老输怎么办