本篇我会使用VS的控制台程序搭建一个本地的简单的服务器,服务器内容很简单,由于考虑到客户端使用了异步来处理连接的,那么我会在服务器使用同步监听和连接的方法来作为服务端使用,结合微软提供Poll检测机制来提供一个不会阻塞的服务端来不断的侦听和接收客户端的连接和发送数据,这里面的发送数据仅仅为转发客户端发送过来的消息内容,不做过多的任何其他的消息处理,记住,这个服务端仅仅是个Demo,这里我花点时间去搭建一个可以供后面博客一直使用的服务器,里面的内容,可能你读到这里有点不理解,但是相信你读完后面的内容再回头看看这篇的内容应该理解起来不难的.如果你致力于客户端的研究,本节内容可以跳过
- 服务端的核心代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Linq;
using System.Reflection;
namespace Test
{
class MainClass
{
/// <summary>
/// 用来监听的socket
/// </summary>
public static Socket listenfd = null;
public static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
private const string IP = "127.0.0.1";
private const int Port = 8888;
private Queue<string> writeQueue = new Queue<string>();
static void Main(string[] args)
{
Console.WriteLine("这里是Test的服务器哦~");
//创建socket对象
listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定IP地址和端口号
IPAddress ipAdr = IPAddress.Parse(IP);
IPEndPoint ipEp = new IPEndPoint(ipAdr, Port);
//进行绑定
listenfd.Bind(ipEp);
//开始监听
listenfd.Listen(0);
Console.WriteLine("[ 服务器 ] 启动成功啦~");
#region 同步方法 我们使用Poll来检测异常 同步方法可以用来避免引发线程问题,使用Poll来防止阻塞
List<Socket> checkRead = new List<Socket>();
while (true)
{
checkRead.Clear();
checkRead.Add(listenfd);
foreach (ClientState s in clients.Values)
{
checkRead.Add(s.socket);
}
//select
Socket.Select(checkRead, null, null, 1000);
//检查可读对象
foreach (Socket s in checkRead)
{
if (s == listenfd)
{
//接收客户端连接
ReadListenfd(listenfd);
}
else
{
//接收客户端消息
ReadClientfd(s);
}
}
}
#endregion
}
private static bool ReadClientfd(Socket clientfd)
{
ClientState state = clients[clientfd];
//接收
int count = 0;
try
{
count = clientfd.Receive(state.readBuff);
}
catch (SocketException ex)
{
MethodInfo mei = typeof(EventHandler).GetMethod("OnDisconnect");
object[] ob = { state };
mei.Invoke(null, ob);
clientfd.Close();
clients.Remove(clientfd);
Console.WriteLine("Receive SocketException " + ex.ToString());
}
//客户端关闭
if (count <= 0)
{
MethodInfo mei = typeof(EventHandler).GetMethod("OnDisconnect");
object[] ob = { state };
mei.Invoke(null, ob);
clientfd.Close();
clients.Remove(clientfd);
Console.WriteLine("Socket Close !!!");
return false;
}
#region 粘包问题处理
//显示
string recvStr = System.Text.Encoding.UTF8.GetString(state.readBuff, 2, count - 2);
Console.WriteLine("Receive " + recvStr);
//广播给其他的客户端
byte[] sendBytes = new byte[count];
Array.Copy(state.readBuff, 0, sendBytes, 0, count);
foreach (var cs in clients.Values)
{
cs.socket.Send(sendBytes);//减少代码量,不用异步发送
}
#endregion
return true;
}
private static void ReadListenfd(Socket listenfd)
{
Console.WriteLine("Accept ");
Socket clientfd = listenfd.Accept();
ClientState state = new ClientState();
state.socket = clientfd;
clients.Add(clientfd, state);
}
}
}
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
public class ClientState
{
public Socket socket = null;
public byte[] readBuff = new byte[1024];
}
}