为了准备毕业设计,学习了服务器与客户端之间传输的一些简单的知识,并跟着网络上的教程制作了一个简易的Unity聊天室
服务器:用C# .Net Framework写的
结构分为:main(主函数)、Server类(用于服务器的开启和接收客户端连接)、Client类(接收消息和发送消息)、Message类(用于消息的解析和包装)
main:
static void Main(string[] args)
{
string ip = "127.0.0.1"; //这个ip地址表示本机
int port = 6688; //测试用的端口号,应该可以自己随便写吧
Server server = new Server(ip, port);
server.Start();
Console.ReadKey();
}
Server:
public class Server
{
private Socket serverSocket = null;
private List<Client> clientList = new List<Client>();
private Socket clientSocket = null;
public Server() { }
public Server(string ip,int port)
{
//创建socket,然后绑定ip地址和端口号
//传输类型是流,使用的协议是Tcp
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
EndPoint point = new IPEndPoint(IPAddress.Parse(ip), port);
serverSocket.Bind(point);
}
public void Start()
{
serverSocket.Listen(0); //开始监听 0表示等待连接队列的最大数
Console.WriteLine("开始监听");
Console.WriteLine("等待客户端连接");
serverSocket.BeginAccept(AcceptCallBack, null); //等待客户端连接,AcceptCallBack是回调,第三个参数目前还没用过,没去了解作用 TODO
}
private void AcceptCallBack(IAsyncResult ar)
{
clientSocket = serverSocket.EndAccept(ar);
Console.WriteLine("一个客户端连接");
Client client = new Client(clientSocket,this); //当客户端连接上后,用Client类处理消息的接收与发送
clientList.Add(client);
client.Start();//开始接收消息
serverSocket.BeginAccept(AcceptCallBack, null); //服务器继续等待其他客户端连接
}
public void Broadcast(string message) //广播消息
{
foreach(Client client in clientList)
{
client.SendMessage(message);
}
}
}
Client:
public class Client
{
private Socket clientSocket;
private Server server;
private Message msg = new Message();
public Client() { }
public Client(Socket clientSocket,Server server)
{
this.clientSocket = clientSocket;
this.server = server;
}
public void Start()
{
//判断客户端是否被关闭
if (clientSocket.Connected == false || clientSocket.Poll(10, SelectMode.SelectRead))
{
clientSocket.Close();
return;
}
//等待从客户端的消息的接收
clientSocket.BeginReceive(msg.data, 0, msg.data.Length, SocketFlags.None, ReceiveCallBack, null);
}
private void ReceiveCallBack(IAsyncResult ar)
{
try
{
//需要用try catch 捕捉异常,不然出现异常服务器会终止
//判断客户端是否被关闭
if (clientSocket.Connected==false || clientSocket.Poll(10,SelectMode.SelectRead))
{
clientSocket.Close();
return;
}
int len = clientSocket.EndReceive(ar); //返回的len表示接收的数据长度
if (len == 0) //客户端被关闭了 服务端会接收到0字节的消息
{
clientSocket.Close();
return;
}
msg.Read(len, OnProessMassage);//Message类解析消息
//Console.WriteLine("receive:" + message);
clientSocket.BeginReceive(msg.data, 0, msg.data.Length, SocketFlags.None, ReceiveCallBack, null);
}
catch (Exception e)
{
Console.WriteLine("ReceiveCallBack:" + e);
}
}
private void OnProessMassage(string msg)
{
server.Broadcast(msg);//通过服务器广播消息
}
public void SendMessage(string message)
{
//判断客户端是否被关闭 发送的时候客户端也可能被关闭
if (clientSocket.Connected == false || clientSocket.Poll(10, SelectMode.SelectRead))
{
clientSocket.Close();
return;
}
clientSocket.Send(msg.Pack(message)); //发送消息给客户端
//Console.WriteLine("send:"+message);
}
}
Message:
//这里只是简单的处理消息;解析:从byte[] ->string;发送:string->byte[]
class Message
{
public byte[] data = new byte[1024];
public void Read(int len,Action<string>OnProessMessage)
{
string message = Encoding.UTF8.GetString(data, 0, len);
OnProessMessage(message);
Array.Clear(data, 0, len);
}
public byte[] Pack(string msg)
{
byte[] dataBytes = Encoding.UTF8.GetBytes(msg);
return dataBytes;
}
}