版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_15020543/article/details/84033502
上篇博客已经完成了简单的交互,但是在正常情况下,一个服务器要监听多个客户端,服务器端和客户端的交互也是非常频繁的。所以就要有异步操作,来持续监听。
1.监听多个客户端连接,只需要在AcceptCallBack这一回调函数里再次BeginAccept即可
2.异步接收数据,BeginReceive
为此,我们可以新建一个Message类,用来解析接收到的数据。这个Message类,两个项目都要导入。
我们约定,传递的字节,前面是数字(占4位),后面是字符串(套接字(Socket),忽然发现为啥叫套接字)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ClientTest
{
class Message
{
private byte[] data = new byte[1024];
private int startIndex = 0;//我们存取了多少个字节的数据在数组里面
public void AddCount(int count)
{
startIndex += count;
}
public byte[] Data
{
get { return data; }
}
public int StartIndex
{
get
{
return startIndex;
}
}
public int RemindSize
{
get
{
return data.Length - startIndex;
}
}
//解析数据
public void ReadMessage()
{
while (true)
{
if (startIndex <= 4)
{
return;
}
int count = BitConverter.ToInt32(data, 0);
if ((startIndex - 4) >= count)
{
string s = Encoding.UTF8.GetString(data, 4, count);
Console.WriteLine("解析出来一条数据:" + s);
Array.Copy(data, count + 4, data, 0, startIndex - 4 - count);
startIndex -= (count + 4);
}
else
{
break;
}
}
}
/// <summary>
/// 得到数据的约定形式
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] GetBytes(string data)
{
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
int dataLength = dataBytes.Length;
byte[] lengthBytes = BitConverter.GetBytes(dataLength);
byte[] Bytes = lengthBytes.Concat(dataBytes).ToArray();
return Bytes;
}
}
}
重写服务器端和客户端
服务器端
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Server
{
class Program
{
/// <summary>
/// 实例化Message
/// </summary>
static Message rec_Message = new Message();
static Socket serverSocket;
static void Main(string[] args)
{
StartServer();
//暂停
Console.ReadKey();
}
/// <summary>
/// 开启一个Socket
/// </summary>
static void StartServer()
{
//实例化一个Socket
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//设置IP
IPAddress ipAdress = IPAddress.Parse("127.0.0.1");
//设置网络终结点
IPEndPoint iPEndPoint = new IPEndPoint(ipAdress, 88);
//绑定ip和端口号
serverSocket.Bind(iPEndPoint);
//等待队列(开始监听端口号)
serverSocket.Listen(0);
//异步接受客户端连接
serverSocket.BeginAccept(AcceptCallBack, serverSocket);
}
/// <summary>
/// 开始发送数据到客户端
/// </summary>
/// <param name="toClientsocket">用以连接客户端的Socket</param>
/// <param name="msg">要传递的数据</param>
static void BeginSendMessagesToClient(Socket toClientsocket,string msg)
{
toClientsocket.Send(Message.GetBytes(msg));
}
/// <summary>
/// 开始接收来自客户端的数据
/// </summary>
/// <param name="toClientsocket"></param>
static void BeginReceiveMessages(Socket toClientsocket)
{
toClientsocket.BeginReceive(rec_Message.Data, rec_Message.StartIndex, rec_Message.RemindSize, SocketFlags.None, ReceiveCallBack, toClientsocket);
}
/// <summary>
/// 当客户端连接到服务器时执行的回调函数
/// </summary>
/// <param name="ar"></param>
static void AcceptCallBack(IAsyncResult ar)
{
//这里获取到的是向客户端收发消息的Socket
Socket toClientsocket = serverSocket.EndAccept(ar);
Console.WriteLine("客户端{0}连接进来了。",toClientsocket.RemoteEndPoint.ToString());
//要向客户端发送的消息
string msg = "Hello client!你好。";
//开始发送消息
BeginSendMessagesToClient(toClientsocket, msg);
//开始接收客户端传来的消息
BeginReceiveMessages(toClientsocket);
////继续等待下一个客户端的链接
serverSocket.BeginAccept(AcceptCallBack, serverSocket);
}
/// <summary>
/// 接收到来自客户端消息的回调函数
/// </summary>
/// <param name="ar"></param>
static void ReceiveCallBack(IAsyncResult ar)
{
Socket toClientsocket = null;
try
{
toClientsocket = ar.AsyncState as Socket;
int count = toClientsocket.EndReceive(ar);
if (count == 0)
{
toClientsocket.Close();
return;
}
Console.WriteLine("从客户端:{0} 接收到数据,解析中。。。",toClientsocket.RemoteEndPoint);
rec_Message.AddCount(count);
//打印来自客户端的消息
rec_Message.ReadMessage();
BeginSendMessagesToClient(toClientsocket, "客户端"+toClientsocket.RemoteEndPoint+"我收到了你消息。");
//继续监听来自客户端的消息
toClientsocket.BeginReceive(rec_Message.Data, rec_Message.StartIndex, rec_Message.RemindSize, SocketFlags.None, ReceiveCallBack, toClientsocket);
}
catch (Exception e)
{
Console.WriteLine(e);
if (toClientsocket != null)
{
toClientsocket.Close();
}
}
finally
{
}
}
}
}
客户端
using System;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace ClientTest
{
class Program
{
/// <summary>
/// 实例化Message
/// </summary>
static Message rec_Message = new Message();
//声明客户端
static Socket clientSocket;
static void Main(string[] args)
{
StartClient();
while (true)
{
Console.WriteLine("请输入想要向服务器发送的字符串:");
string data = Console.ReadLine();
BeginSendMessagesToServer(data);
}
}
/// <summary>
/// 开启客户端并连接到服务器端
/// </summary>
static void StartClient()
{
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
clientSocket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 88));
Console.WriteLine("连接服务器成功");
}
catch (Exception e)
{
Console.WriteLine(e);
Console.WriteLine("连接服务器失败");
}
BeginSendMessagesToServer("Hello,服务器端。");
BeginReceiveMessages();
}
/// <summary>
/// 开始发送数据到客户端
/// </summary>
/// <param name="msg">要传递的数据</param>
static void BeginSendMessagesToServer(string msg)
{
try
{
clientSocket.Send(Message.GetBytes(msg));
Console.WriteLine("{0} 发送成功!",msg);
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
/// <summary>
/// 开始接收来自客户端的数据
/// </summary>
/// <param name="toClientsocket"></param>
static void BeginReceiveMessages()
{
clientSocket.BeginReceive(rec_Message.Data, rec_Message.StartIndex, rec_Message.RemindSize, SocketFlags.None, ReceiveCallBack, null);
}
/// <summary>
/// 接收到来自服务端消息的回调函数
/// </summary>
/// <param name="ar"></param>
static void ReceiveCallBack(IAsyncResult ar)
{
try
{
int count = clientSocket.EndReceive(ar);
Console.WriteLine("从客户端接收到数据,解析中。。。");
rec_Message.AddCount(count);
//打印来自客户端的消息
rec_Message.ReadMessage();
//继续监听来自服务端的消息
clientSocket.BeginReceive(rec_Message.Data, rec_Message.StartIndex, rec_Message.RemindSize, SocketFlags.None, ReceiveCallBack, null);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
}
测试,我们要把客户端和服务器端都打包成exe文件。
点重新生成
客户端打包同上