.net Socket 网络编程(四)

 在(三)中我们用多线程简单实现了异步,这里用微软为我们提供的IAsyncResult模式来实现

现在代码增多了,把处理套接字的部分单独创建一个类SocketServer
代码如下,同时仍然保留了同步的Listen方法,这里异步的监听命名为AsyncListen

class  SocketServer
    
{
        
private int _port;
        
private string _ip;
        
private string _hostName;
        
private int _backlog; //队列连接数

    
private IPEndPoint ipEndPoint;
        
private IPAddress ipAddress;
        
private IPHostEntry ipHostEntry;
        
private Socket listener;

        
public int Port
        
{
            
get return _port; }
            
set { _port = value; }
        }

        
public int BackLog
        
{
            
get return _backlog; }
            
set { _backlog = value; }
        }

        
public string IP
        
{
            
get return _ip; }
            
set { _ip = value; }
        }

        
public string HostName
        
{
            
get return _hostName; }
            
set { _hostName = value; }
        }
    


        
public UploadServer()
        
{
            listener 
= null;
            _ip 
= "127.0.0.1";
            _port 
= 7788;
            _backlog 
= 10;
            _hostName 
= String.Empty;
        }


        
/// <summary>
        
/// 初始化服务器地址
    
/// </summary>

        private void InitIPInfo()
        
{
            
if (_ip == String.Empty)
            
{
                
if (_hostName != String.Empty)
                
{
                    ipHostEntry 
= Dns.GetHostEntry(_hostName);
                    ipAddress 
= ipHostEntry.AddressList[0];
                }

                
else
                
{
                    
throw new Exception("未指定有效服务器地址");
                }

            }

            
else
            
{
                ipAddress 
= IPAddress.Parse(_ip);
                ipHostEntry 
= Dns.GetHostEntry(ipAddress);
            }

            ipEndPoint 
= new IPEndPoint(ipAddress, _port);
        }


        
public void Listen()
        
{
            InitIPInfo();
            listener 
= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            listener.Bind(ipEndPoint);
            listener.Listen(_backlog);
            Console.WriteLine(
"服务启动,开始监听");
            Console.WriteLine(
"等待客户端连接...");

            Socket clientSocket 
= listener.Accept();
            Console.WriteLine(
"建立连接");

            
// 接受数据
      byte[] buffer = new byte[1024];
            clientSocket.Receive(buffer);
            Console.WriteLine(
"接受客户端信息:{0}", Encoding.GetEncoding("gb2312").GetString(buffer));
            
//回复客户端
      byte[] backBuffer = new byte[1024];
            
string backString = "收到数据";

            backBuffer 
= Encoding.GetEncoding("gb2312").GetBytes(backString);
            clientSocket.Send(backBuffer);

            clientSocket.Shutdown(SocketShutdown.Both);
            clientSocket.Close();
            Console.WriteLine(
"关闭客户端连接");
        }


        
public void AsyncListen()
        
{
            InitIPInfo();

            listener 
= new Socket(ipEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            listener.Bind(ipEndPoint);
            listener.Listen(_backlog);

            Console.WriteLine(
"服务启动,开始监听");
            Console.WriteLine(
"等待客户端连接...");

            listener.BeginAccept(
new AsyncCallback(acceptCallback), listener);
        }


        
private void acceptCallback(IAsyncResult ar) 
        
{
            Socket listener 
= (Socket)ar.AsyncState;
            Socket clientSocket 
= listener.EndAccept(ar); //获得客户端套接字接口
      Console.WriteLine("建立连接");

            StateObject state 
= new StateObject();
            state.WorkSocket 
= clientSocket;
            clientSocket.BeginReceive(state.buffer, 
0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state); //开始接受数据
        }


        
public class StateObject
        
{
            
public Socket WorkSocket = null;
            
public static int BufferSize = 1024;
            
public byte[] buffer = new byte[BufferSize];
        }


        
//结束挂起的异步读取
        public static void readCallback(IAsyncResult ar)
        
{
            StateObject state 
= (StateObject)ar.AsyncState;
            Socket clientSocket 
= state.WorkSocket;

            
if (clientSocket.Connected)
            
{
                
int read = clientSocket.EndReceive(ar);//结束挂起的异步读取


        
//一直接受数据到没有为止
        if (read > 0)
                
{
                    clientSocket.BeginReceive(state.buffer, 
0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state);
                }


                Console.WriteLine(
"接受客户端信息:{0}", Encoding.GetEncoding("gb2312").GetString(state.buffer));
                
//回复客户端
                byte[] backBuffer = new byte[1024];
                
string backString = "收到数据";

                backBuffer 
= Encoding.GetEncoding("gb2312").GetBytes(backString);
                clientSocket.Send(backBuffer);
                clientSocket.Close();
            }

            
else
            
{
                Console.WriteLine(
"连接已经关闭!");
            }

            
        }


    }

在Program.cs如下调用

SocketServer us = new SocketServer();
us.AsyncListen();

OK运行查看效果

上面的例子基本实现,实际存在问题还很多
比如
如果客户端传送的数据一次接受不完
没有服务器端向客户端发送信息
而且判断是否接受完客户端数据上面的例子也有问题,下面来完善一下

class  SocketServer
    
{
        
private int _port;
        
private string _ip;
        
private string _hostName;
        
private int _backlog; //队列连接数

    
private IPEndPoint ipEndPoint;
        
private IPAddress ipAddress;
        
private IPHostEntry ipHostEntry;
        
private Socket listener;

        
private static ManualResetEvent allDone = new ManualResetEvent(false);

        
public int Port
        
{
            
get return _port; }
            
set { _port = value; }
        }

        
public int BackLog
        
{
            
get return _backlog; }
            
set { _backlog = value; }
        }

        
public string IP
        
{
            
get return _ip; }
            
set { _ip = value; }
        }

        
public string HostName
        
{
            
get return _hostName; }
            
set { _hostName = value; }
        }


        
public class StateObject
        
{
            
public Socket WorkSocket = null;
            
public static int BufferSize = 2;
            
public byte[] buffer = new byte[BufferSize];
            
public StringBuilder sb = new StringBuilder();
        }


        
public SocketServer()
        
{
            listener 
= null;
            _ip 
= "127.0.0.1";
            _port 
= 7788;
            _backlog 
= 10;
            _hostName 
= String.Empty;

        }


        
/// <summary>
        
/// 初始化服务器地址
    
/// </summary>

        private void InitIPInfo()
        
{
            
if (_ip == String.Empty)
            
{
                
if (_hostName != String.Empty)
                
{
                    ipHostEntry 
= Dns.GetHostEntry(_hostName);
                    ipAddress 
= ipHostEntry.AddressList[0];
                }

                
else
                
{
                    
throw new Exception("未指定有效服务器地址");
                }

            }

            
else
            
{
                ipAddress 
= IPAddress.Parse(_ip);
                ipHostEntry 
= Dns.GetHostEntry(ipAddress);
            }

            ipEndPoint 
= new IPEndPoint(ipAddress, _port);
        }


        
public void Listen()
        
{
            InitIPInfo();
            listener 
= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            listener.Bind(ipEndPoint);
            listener.Listen(_backlog);
            Console.WriteLine(
"服务启动,开始监听");
            Console.WriteLine(
"等待客户端连接...");

            Socket clientSocket 
= listener.Accept();
            Console.WriteLine(
"建立连接");

            
// 接受数据
      byte[] buffer = new byte[1024];
            clientSocket.Receive(buffer);
            Console.WriteLine(
"接受客户端信息:{0}", Encoding.GetEncoding("gb2312").GetString(buffer));
            
//回复客户端
            byte[] backBuffer = new byte[1024];
            
string backString = "收到数据";

            backBuffer 
= Encoding.GetEncoding("gb2312").GetBytes(backString);
            clientSocket.Send(backBuffer);

            clientSocket.Shutdown(SocketShutdown.Both);
            clientSocket.Close();
            Console.WriteLine(
"关闭客户端连接");
        }


        
public void AsyncListen()
        
{
            InitIPInfo();

            listener 
= new Socket(ipEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            
try
            
{
                listener.Bind(ipEndPoint);
                listener.Listen(_backlog);

                Console.WriteLine(
"服务启动,开始监听");
                Console.WriteLine(
"等待客户端连接...");
                
while (true)
                
{
                    allDone.Reset();
                    listener.BeginAccept(
new AsyncCallback(acceptCallback), listener);
                    allDone.WaitOne();
                }

            }

            
catch (Exception ex)
            
{
                Console.WriteLine(
"发生错误:"+ex.Message);
            }

            
        }


        
private void acceptCallback(IAsyncResult ar) 
        
{
            Console.WriteLine(
"acceptCallback 被调用");
            Socket listener 
= (Socket)ar.AsyncState;
            Socket clientSocket 
= listener.EndAccept(ar); //获得客户端套接字接口
      Console.WriteLine("建立连接");
            allDone.Set();

            StateObject state 
= new StateObject();
            state.WorkSocket 
= clientSocket;
            clientSocket.BeginReceive(state.buffer, 
0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state); //开始接受数据

        }


        
public void readCallback(IAsyncResult ar)
        
{
            StateObject state 
= (StateObject)ar.AsyncState;
            Socket clientSocket 
= state.WorkSocket;

            
try
            
{
                
int read = 0;
                read 
= clientSocket.EndReceive(ar);//结束挂起的异步读取

        
if (read > 0)
                
{
                    state.sb.Append(Encoding.GetEncoding(
"gb2312").GetString(state.buffer, 0, read));
                    Console.WriteLine(state.sb.ToString());

                    
if (state.sb.ToString().IndexOf("<end>"> -1)
                    
{

                        Console.WriteLine(
"已经接收完数据");
                        
//回复客户端
            byte[] backBuffer = new byte[1024];
                        
string backString = "已经收到数据";

                        backBuffer 
= Encoding.GetEncoding("gb2312").GetBytes(backString);
                        clientSocket.BeginSend(backBuffer, 
0, backBuffer.Length, SocketFlags.None, new AsyncCallback(SendCallback), state);
                    }

                    
else
                    
{
                        clientSocket.BeginReceive(state.buffer, 
0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state);
                    }

                }

            }

            
catch (SocketException se)
            
{
                
if (se.ErrorCode == 10054)
                
{
                    Console.WriteLine(
"客户端已断开连接!");
                }

                
else
                
{
                    Console.WriteLine(se.Message);
                }

            }

            
catch (Exception ex)
            
{
                Console.WriteLine(ex.Message);
            }


            
        }


        
private void SendCallback(IAsyncResult ar)
        
{
            Console.WriteLine(
"SendCallback 被调用");
            
try
            
{
                StateObject state 
= (StateObject)ar.AsyncState;
                Socket handle 
= state.WorkSocket;
                
int bytesSent = handle.EndSend(ar);
                Console.WriteLine(
"发送到客户端 {0}", bytesSent);
                Console.WriteLine(
"接受客户端信息:{0}",state.sb.ToString() );
                handle.Shutdown(SocketShutdown.Both);
                handle.Close();

            }

            
catch (Exception e)
            
{
                Console.WriteLine(e.ToString());
            }

        }


    }


这里判断客户端传送数据是否接受完成时个比较麻烦的问题
这里在客户端传入的字符串中用了<end>标志来判断
如果使用EndReceive的返回值是否大于1来判断会出现无法调用委托方法的情况也不报错
因为当没有数据传输到服务器端的时候BeginReceive并不会调用委托
自己感觉靠添加额外定制符号的办法不是很让人舒服,暂时也没有其他好的解决办法,如果有朋友知道告诉我一下哈:)

下面贴出客户端修改为异步以后的代码

     public   class  StateObject
    
{
        
public Socket workSocket = null;
        
public static int BufferSize = 1024;
        
public byte[] buffer = new byte[BufferSize];
        
public StringBuilder sb = new StringBuilder();
    }



    
class  SocketClient
    
{
        
private int _port;
        
private string _ip;
        
private string _hostName;

        
private IPEndPoint ipEndPoint;
        
private IPAddress ipAddress;
        
private IPHostEntry ipHostEntry;

        
private static ManualResetEvent connectDone = new ManualResetEvent(false);
        
private static ManualResetEvent sendDone = new ManualResetEvent(false);
        
private static ManualResetEvent receiveDone = new ManualResetEvent(false);
        
private static String response = String.Empty; //服务器返回的信息

        
public int Port
        
{
            
get return _port; }
            
set { _port = value; }
        }

        
public string IP
        
{
            
get return _ip; }
            
set { _ip = value; }
        }

        
public string HostName
        
{
            
get return _hostName; }
            
set { _hostName = value; }
        }


        
private void InitIPInfo()
        
{
            
if (_ip == String.Empty)
            
{
                
if (_hostName != String.Empty)
                
{
                    ipHostEntry 
= Dns.GetHostEntry(_hostName);
                    ipAddress 
= ipHostEntry.AddressList[0];
                }

                
else
                
{
                    
throw new Exception("未指定有效服务器地址");
                }

            }

            
else
            
{
                ipAddress 
= IPAddress.Parse(_ip);
                ipHostEntry 
= Dns.GetHostEntry(ipAddress);
            }

            ipEndPoint 
= new IPEndPoint(ipAddress, _port);
        }


        
public UploadClient()
        
{
            _ip 
= "127.0.0.1";
            _port 
= 7788;
            _hostName 
= String.Empty;
        }


        
public void Connect()
        
{
            InitIPInfo();

            
try
            
{
                
///创建socket并连接到服务器
                Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                Console.WriteLine(
"等待连接…");
                serverSocket.Connect(ipEndPoint);
//连接到服务器
                Console.WriteLine("已连接");

                
//发送数据
                byte[] buffer = new byte[1024];
                buffer 
= Encoding.GetEncoding("gb2312").GetBytes("Godling is a good man!<end>");
                serverSocket.Send(buffer);

                
//接受数据
                byte[] bufferGet = new byte[1024];
                serverSocket.Receive(bufferGet);
                Console.WriteLine(
"接受服务端信息:{0}", Encoding.GetEncoding("gb2312").GetString(bufferGet));

                serverSocket.Shutdown(SocketShutdown.Both);
                serverSocket.Close();

            }

            
catch (ArgumentNullException e)
            
{
                Console.WriteLine(
"argumentNullException: {0}", e);
            }

            
catch (SocketException e)
            
{
                Console.WriteLine(
"SocketException:{0}", e);
            }


            Console.WriteLine(
"Press Enter to Exit");
        }


        
//开始异步连接
        public void AsyncConnect()
        
{
            
try
            
{
                InitIPInfo();

                Socket serverSocket 
= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                serverSocket.BeginConnect(ipEndPoint, 
new AsyncCallback(ConnectCallback), serverSocket);
                connectDone.WaitOne(); 
//阻止运行直到连接成功

                
//发送数据
                string data = "你能收到我吗?<end>";
                
byte[] byteData = Encoding.GetEncoding("gb2312").GetBytes(data);
                serverSocket.BeginSend(byteData, 
0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), serverSocket);
                sendDone.WaitOne();


                StateObject state 
= new StateObject();
                state.workSocket 
= serverSocket;
                serverSocket.BeginReceive(state.buffer, 
0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
                receiveDone.WaitOne();
                Console.WriteLine(
"接收到服务器信息:{0}", response);

                serverSocket.Shutdown(SocketShutdown.Both);
                serverSocket.Close();
            }

            
catch(Exception ex)
            
{
                Console.WriteLine(
"发生异常"+ex.Message);
            }


        }


        
// 连接完成回调方法
        private void ConnectCallback(IAsyncResult ar)
        
{
            
try
            
{
                Socket serverSocket 
= (Socket)ar.AsyncState;
                serverSocket.EndConnect(ar);
                Console.WriteLine(
"已连接到{0}",serverSocket.RemoteEndPoint.ToString());

                connectDone.Set();
            }

            
catch (Exception e)
            
{
                Console.WriteLine(
"连接错误!"+e.ToString());
            }


        }


        
// 数据发送回调方法
        private static void SendCallback(IAsyncResult ar)
        
{
            
try
            
{
                Socket serverSocket 
= (Socket)ar.AsyncState;
                
int bytesSent = serverSocket.EndSend(ar);
                Console.WriteLine(
"向服务器发送数据 {0} bytes", bytesSent);

                sendDone.Set();
            }

            
catch (Exception e)
            
{
                Console.WriteLine(e.ToString());
            }

        }


        
// 接收数据回调方法
        private static void ReceiveCallback(IAsyncResult ar)
        
{
            StateObject state 
= (StateObject)ar.AsyncState;
            Socket serverSocket 
= state.workSocket;

            
int read = 0;

            
if (serverSocket.Connected)
            
{
                read 
= serverSocket.EndReceive(ar);
            }

            
if (read > 0)
            
{
                state.sb.Append(Encoding.GetEncoding(
"gb2312").GetString(state.buffer, 0, read));
                
try
                
{
                    serverSocket.BeginReceive(state.buffer, 
0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
                }

                
catch (SocketException se)
                
{
                    
if (se.ErrorCode == 10054)
                    
{
                        Console.WriteLine(
"远程主机已经断开连接!");
                    }

                }

            }

            
else
            
{
                
if (state.sb.Length > 1)
                
{
                    response 
= state.sb.ToString();
                }

                receiveDone.Set();
            }

            
        }





    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值