本章主要讲述如何使用VS控制台程序创建服务器,使用Unity创建客户端,然后实现消息的同步以及异步接收与发送。
一 同步与异步的区别
简单来说,同步就是进行一种操作,在操作没结束前不能进行其它操作。这就好比与记录10个学生跑400米需要多少时间,让一个学生起跑后,必须等到他跑完才能让下一个同学起跑。而异步则是在进行某种操作后,可以继续进行下一个操作,也就是在让一个同学起跑后再让下一个同学起跑。异步与同步相比,效率高,但是管理复杂。
二 服务端业务逻辑
用VS新建C#控制台项目TCP_Sever,添加Sever类。
Sever.cs
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace TCP_Sever
{
class Sever
{
/// <summary>
/// 服务器套接字
/// </summary>
private static Socket sever_socket;
/// <summary>
/// 最大连接数
/// </summary>
private static int maxConn = 50;
/// <summary>
/// 数据缓存池
/// </summary>
private static byte[] readBuff = new byte[1024];
/// <summary>
/// 开启服务器
/// </summary>
/// <param name="host">IP地址</param>
/// <param name="port">端口号</param>
public static void Start(string IP, int port)
{
//创建服务器套接字
sever_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定IP和端口号
IPAddress ip = IPAddress.Parse(IP);
IPEndPoint point = new IPEndPoint(ip, port);
sever_socket.Bind(point);
//监听,0无限制
sever_socket.Listen(maxConn);
Console.WriteLine("服务器开启成功");
}
/// <summary>
/// 同步接收与发送
/// </summary>
public static void SynRecv_Send()
{
//客户端接入
if (sever_socket == null)
{
Console.WriteLine("请先开启服务器");
return;
}
Socket connfd = sever_socket.Accept();
Console.WriteLine("客户端接入");
//获取接收到的流转换为字符串
int count;
try
{
count= connfd.Receive(readBuff);
}
catch (Exception e)
{
Console.WriteLine("客户端异常"+e.Message);
return;
}
string str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
Console.WriteLine("收到信息:" + str);
//获取输入,发送给客户端
str="服务器接收到消息:"+str;
byte[] writeBuff = System.Text.Encoding.UTF8.GetBytes(str);
connfd.Send(writeBuff);
connfd.Close();
}
/// <summary>
/// 异步接收
/// </summary>
public static void AsynRec()
{
//客户端接入
if (sever_socket == null)
{
Console.WriteLine("请先开启服务器");
return;
}
Socket connfd = sever_socket.Accept();
Console.WriteLine("客户端接入");
//异步接收
try
{
connfd.BeginReceive(readBuff, 0, 1024, SocketFlags.None,AsynReceiveCallBack, connfd);
}
catch (Exception e)
{
Console.WriteLine("客户端异常"+e.Message);
return;
}
}
/// <summary>
/// 异步接收回调
/// </summary>
/// <param name="ar"></param>
private static void AsynReceiveCallBack(IAsyncResult ar)
{
try
{
//获得客户端套接字
Socket clientSocket = ar.AsyncState as Socket;
int count = clientSocket.EndReceive(ar);
string str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
Console.WriteLine("接收到消息:" + str);
AsynSend(clientSocket);
//继续接收,实现循环
clientSocket.BeginReceive(readBuff, 0, 1024, SocketFlags.None, AsynReceiveCallBack, clientSocket);
}
catch (Exception e)
{
Console.WriteLine("客户端断开:" + e.Message);
}
}
/// <summary>
/// 异步发送
/// </summary>
public static void AsynSend(Socket clientsocket)
{
//客户端接入
if (sever_socket == null)
{
Console.WriteLine("请先开启服务器");
return;
}
byte[] writerBuff = System.Text.Encoding.UTF8.GetBytes("客户端你好");
try
{
//异步发送
clientsocket.BeginSend(writerBuff, 0, writerBuff.Length, SocketFlags.None, null, null);
}
catch (Exception e)
{
Console.WriteLine("发送消息失败" + e.Message);
}
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TCP_Sever
{
class Program
{
static void Main(string[] args)
{
Sever.Start("127.0.0.1", 6688);
while (true)
{
//同步
//Sever.SynRecv_Send();
//异步
Sever.AsynRec();
}
}
}
}
三 客户端端业务逻辑
打开Unity,新建Client和Manager类。将Manager挂载在场景的空物体上。
Client.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System;
namespace YCX_Tool.Client
{
public class Client
{
/// <summary>
/// 客户端套接字
/// </summary>
private static Socket client_socket;
/// <summary>
/// 数据缓存池
/// </summary>
private static byte[] readBuff = new byte[1024];
/// <summary>
/// 连接服务器
/// </summary>
/// <param name="IP"></param>
/// <param name="Port"></param>
public static void Start(string IP, int Port)
{
//创建客户端套接字
client_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//连接
try
{
client_socket.Connect(IP, Port);
Debug.Log("服务端连接");
}
catch (System.Exception e)
{
Debug.Log(e.Message);
}
}
/// <summary>
/// 同步接收与发送
/// </summary>
public static void SynRecv_Send()
{
if (client_socket == null)
{
Debug.Log("请先开启客户端");
return;
}
//发送
string str = "Hello Unity";
byte[] writeBuff = System.Text.Encoding.UTF8.GetBytes(str);
client_socket.Send(writeBuff);
//接收
try
{
int count = client_socket.Receive(readBuff);
str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
Debug.Log("接收到消息:" + str);
}
catch (System.Exception e)
{
Debug.Log("接收异常" + e.Message);
}
}
/// <summary>
/// 异步接收
/// </summary>
public static void AsynRec()
{
//客户端接入
if (client_socket == null)
{
Debug.Log("请先开启服务器");
return;
}
//异步接收
try
{
client_socket.BeginReceive(readBuff, 0, 1024, SocketFlags.None, AsynReceiveCallBack, null);
}
catch (Exception e)
{
Debug.Log("客户端异常" + e.Message);
return;
}
}
/// <summary>
/// 异步接收回调
/// </summary>
/// <param name="ar"></param>
private static void AsynReceiveCallBack(IAsyncResult ar)
{
try
{
//获得客户端套接字
int count = client_socket.EndReceive(ar);
string str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
Debug.Log("接收到消息:" + str);
//继续接收,实现循环
client_socket.BeginReceive(readBuff, 0, 1024, SocketFlags.None, AsynReceiveCallBack, null);
}
catch (Exception e)
{
Debug.Log("服务器断开:" + e.Message);
}
}
/// <summary>
/// 异步发送
/// </summary>
public static void AsynSend()
{
//客户端接入
if (client_socket == null)
{
Debug.Log("请先开启服务器");
return;
}
byte[] writerBuff = System.Text.Encoding.UTF8.GetBytes("服务端你好");
try
{
//异步发送
client_socket.BeginSend(writerBuff, 0, writerBuff.Length, SocketFlags.None, null, null);
}
catch (Exception e)
{
Debug.Log("发送消息失败" + e.Message);
}
}
}
}
Manager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YCX_Tool.Client;
public class Manager : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Client.Start("127.0.0.1", 6688);
Client.AsynRec();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
Client.AsynSend();
}
}
}