异步通信:
之前写得聊天室是基于同步通信的,使用的Socket.Accept(), Socket.Receive()等方法。同步的方法实现起来简单,但是它是在一个任务处理完之后,然后才能再进行接收。现在使用异步的方法来实现它,当一个任务正在进行中时,又有一个任务进来,那么就会另开一个线程来处理它,使得可以同时进行几个会话。
同样使用控制台来实现一个聊天室
服务端:
声明一个静态方法StartServer,用来声明Socket,绑定IP和端口,并开始监听10台计算机
static void BindIP()
{
//声明服务器端的Socket
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//声明IP地址和端口号
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
EndPoint ipEndPoint = new IPEndPoint(ipAddress,7788);
//将serverSocket和IP终节点进行绑定
serverSocket.Bind(ipEndPoint);
//监听最大的接入量为10
serverSocket.Listen(10);
//开始异步连接
serverSocket.BeginAccept(AcceptCallBack,serverSocket);
}
这里serverSocket使用的是BeginAccept()方法,参数要求的是AsyncCallBack(回调方法)和一个Object(对象),这里传入的是回调函数AcceptCallBack和对象serverSocket它本身。
当开启BeginAccept()时,这个方法会开始调用回调方法,并且将后面的Object作为一个参数传入到回调方法中。开始回调方法后,我们要求的后续操作会在回调方法中继续执行。
下面是回调方法AcceptCallBack()
static void AcceptCallBack(IAsyncResult result)
{
//上面讲serverSocket本身传入回调方法中,现在要接收这个Socket。
Socket serverSocket = result.AsyncState as Socket;
//在接收到一台要连入的计算机后,我们要获得接入的计算机的信息,//就需要一个Socket专门用于和它通信。我们再声明一个clientSocket,//用于接收和发送接入方的数据
Socket clientSocket=serverSocket.EndAccept(result);
//在获得这个clientSocket后,使用BeginReceive方法来接收数据
clientSocket.BeginReceive(data,0,1024,SocketFlags.None,ReceiveCallBack, clientSocket);
//建立了通信,开启接收数据后,我们要循环接收其他要连接的计算机,所以这里接着进行等待接收,这样就实现了一个循环不断的接收
serverSocket.BeginAccept(AcceptCallBack, serverSocket);
}
回调方法ReceiveCallBack()
static void ReceiveCallBack(IAsyncResult result)
{
//声明一个空的Socket
Socket clientSocket = null;
//当客户端被暴力关掉后,会造成服务器端的报警,这里将它try catch起来,防止程序崩溃
try
{
//将传入的clientSocket进行接收,并且完成接收数据的操作
clientSocket = result.AsyncState as Socket;
int length = clientSocket.EndReceive(result);
string message = Encoding.UTF8.GetString(data, 0, length);
//如果客户端正常关闭后,会向服务端发送长度为0的空数据,利用这一点将这个客户端关闭
if (length==0)
{
clientSocket.Close();
return;
}
Console.WriteLine("收到消息:" + message);
//重新调用开始接收数据
clientSocket.BeginReceive(data, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
}
catch (Exception e)
{
Console.WriteLine(e);
if(clientSocket!=null)
{
clientSocket.Close();
}
}
}
客户端
跟上一个聊天室一样,除了使用字符c来控制关闭
static Socket clientSocket;
static void Main(string[] args)
{
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
EndPoint ipEndPoint = new IPEndPoint(ipAddress, 7788);
clientSocket.Connect(ipEndPoint);
byte[] dataBuffer = new byte[1024];
while(true)
{
Console.WriteLine("输入数据:");
string s = Console.ReadLine();
//当输入c时,Socket关闭
if(s=="c")
{
clientSocket.Close();
return;
}
dataBuffer = Encoding.UTF8.GetBytes(s);
clientSocket.Send(dataBuffer);
}
Console.ReadKey();
}