操作步骤
- 创建一个类库(不创建控制台应用)
- 创建一个类(服务器类)(ServerPeer)
- 启动服务器
- 绑定Ip和端口号
- 接收客服端的连接
- 处理连接请求
- 创建一个类(客服端类)(ClientServer)
- 创建客服端连接池
- 填满客服端连接池
- 异步处理数据的接收
代码实现如下:
//服务器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
/// <summary>
/// 服务器端
/// </summary>
namespace Card_MyServer
{
public class ServerPeer
{
private Socket serverSocket;
private Semaphore semaphore;//处理请求连接(控制线程)
private ClentPeerPool clientPeerPool;
private void StartServer(string ip, int port, int maxClient)
{
try
{
clientPeerPool = new ClentPeerPool(maxClient);
semaphore = new Semaphore(maxClient, maxClient);
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
for (int i = 0; i < maxClient; i++)//填满客服端连接池
{
ClientPeer clientPeer = new ClientPeer();
clientPeer.ReceiveAsync.Completed += ReceiveAsync_Completed;
clientPeerPool.Enquere(clientPeer);
}
serverSocket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));//绑定IP和端口号
serverSocket.Listen(maxClient);//开始监听 maxClient最大监听数
Console.WriteLine("服务器启动成功!");
//等待连接
StartAccept(null);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
#region 客服端的连接
/// <summary>
/// 接收客服端的连接
/// </summary>
/// <param name="e">异步接收的套接字</param>
private void StartAccept(SocketAsyncEventArgs e)
{
if (e == null)
{
e = new SocketAsyncEventArgs();
e.Completed += E_Completed;
}
//result 为true 代表正在接收连接,连接成功触发 E_Completed方法
//result 为false 代表连接成功
bool result = serverSocket.AcceptAsync(e);
if (result == false)//接收成功 调用处理连接的方法
{
ProcessAccept(e);
}
}
/// <summary>
/// 处理连接请求
/// </summary>
private void ProcessAccept(SocketAsyncEventArgs e)
{
semaphore.WaitOne();//控制线程(比如:两个跑步机只能有两个人,在来的只能等待有一个人走)
ClientPeer client = clientPeerPool.Dequeue();
client.clientSocket = e.AcceptSocket;
Console.WriteLine(client.clientSocket.RemoteEndPoint + "客服端连接成功");
//接收消息
StartReceive(client);
//伪递归 循环接收连接
e.AcceptSocket = null;
StartAccept(e);
}
/// <summary>
/// result为true的时候触发的方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void E_Completed(object sender, SocketAsyncEventArgs e)
{
ProcessAccept(e);
}
#endregion
/// <summary>
/// 开始接收数据
/// </summary>
/// <param name="client"></param>
private void StartReceive(ClientPeer client)
{
try
{
bool result = client.clientSocket.ReceiveAsync(client.ReceiveAsync);
if (result == false)
{
ProcessReceive(client.ReceiveAsync);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
/// <summary>
/// 处理数据的接收
/// </summary>
private void ProcessReceive(SocketAsyncEventArgs e)
{
ClientPeer client = e.UserToken as ClientPeer;
//判断数据是否接收成功
if (client.ReceiveAsync.SocketError==SocketError.Success&&client.ReceiveAsync.BytesTransferred>0)
{
byte[] packet=new byte[client.ReceiveAsync.BytesTransferred];
Buffer.BlockCopy(client.ReceiveAsync.Buffer,0,packet,0, client.ReceiveAsync.BytesTransferred);
//让ClientPeer自身处理接收的数据
client.ProcessReceive(packet);
StartReceive(client);
}
else//断开连接
{
}
}
/// <summary>
/// 异步接收数据完成后的操作
/// </summary>
private void ReceiveAsync_Completed(object sender, SocketAsyncEventArgs e)
{
ProcessReceive(e);
}
}
}
//客服端:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace Card_MyServer
{
public class ClientPeer
{
public Socket clientSocket { get; set; }
public SocketAsyncEventArgs ReceiveAsync { get; set; }//异步接收数据的套接字操作
public ClientPeer()
{
ReceiveAsync = new SocketAsyncEventArgs();
ReceiveAsync.UserToken = this;
ReceiveAsync.SetBuffer(new byte[2048],0,2048);
}
/// <summary>
/// 处理接收到的数据
/// </summary>
public void ProcessReceive(byte[] packet)
{
}
}
}
//客服端连接池
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Card_MyServer
{
public class ClentPeerPool
{
private Queue<ClientPeer> clientPeers;
public ClentPeerPool(int maxCount)
{
clientPeers = new Queue<ClientPeer>(maxCount);
}
public void Enquere(ClientPeer client)
{
clientPeers.Enqueue(client);
}
public ClientPeer Dequeue()
{
return clientPeers.Dequeue();
}
}
}