using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Channels;
using System.Linq;
using System.Net.Http;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using ProtoDataBuff;
using MultiDup;
using pb = global::Google.Protobuf;
namespace clientTest.multiDup
{
class Program
{
static readonly Random r = new Random();
///
/// 消息分发
///
static private Dictionary> callbacks = new Dictionary>();
static void Main(string[] args)
{
callbacks.Add(eProtocalCommand.ScMdGetRoomList, On_update);
callbacks.Add(eProtocalCommand.ScMdEnterRoom, On_enter);
callbacks.Add(eProtocalCommand.ScMdBeginDup, On_begin);
callbacks.Add(eProtocalCommand.ScMdLeaveRoom, On_GameOver);
callbacks.Add(eProtocalCommand.ScMdCreateRoom, On_CreateRoom);
var n = 1;
var list = new Task[n];
for (int i = 0; i < n; i++)
{
list[i] = Task.Run(async () => await send());
}
Task.Run(Dispatch);
Task.WaitAll(list);
}
#region 收到消息处理
///
/// 更新房间列表
///
static void On_update(sSocketData data)
{
Console.WriteLine("最新房间列表: {}");
}
///
/// 客户端进入房间
///
static void On_CreateRoom(sSocketData data)
{
Console.WriteLine("xxx创建了房间.");
}
///
/// 客户端进入房间
///
static void On_begin(sSocketData data)
{
Console.WriteLine("xxx开始了游戏.");
}
///
/// 客户端进入房间
///
static void On_enter(sSocketData data)
{
Console.WriteLine("xx进入了房间.");
}
///
/// 处理客户端上报伤害请求
///
static void On_GameOver(sSocketData data)
{
Console.WriteLine("xx已离开房间! ");
Task.Delay(3000).ContinueWith(t => Environment.Exit(0));
}
#endregion
static async Task send()
{
var port = 6004;
var endPoint = new IPEndPoint(IPAddress.Parse("192.168.10.17"), port);
//var endPoint = new IPEndPoint(IPAddress.Loopback, port);
//var endPoint = new IPEndPoint(IPAddress.Parse("115.159.121.129"), port);
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
try
{
await client.ConnectAsync(endPoint);
}
catch (Exception ee)
{
Debug.WriteLine(ee.Message);
}
var t = Task.Run(() => recv(client)); // 开启recv监听协程
try
{
// 连上来之后, 创建房间, 开始游戏, 退出房间
CreateRoom(client).Wait();
Thread.Sleep(r.Next(1000, 3000));
await BeginGame(client);
Thread.Sleep(r.Next(1000, 3000));
await LeaveGame(client);
Thread.Sleep(r.Next(1000, 3000));
Console.ReadKey();
}
catch (Exception e)
{
client.Close();
}
finally
{
client.Close();
}
}
}
///
/// 创建房间
///
///
///
async static Task CreateRoom(Socket Sock)
{
try
{
var msg = new CS_MD_CreateRoom() { };
var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsMdCreateRoom, IMsg2Bytes(msg)));
await Sock.SendAsync(new ArraySegment(data), SocketFlags.None);
}
catch (Exception e)
{
Sock.Close();
}
}
///
/// 开始游戏
///
///
///
async static Task BeginGame(Socket sock)
{
var msg = new CS_MD_BeginDup() { };
var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsMdBeginDup, IMsg2Bytes(msg)));
await sock.SendAsync(new ArraySegment(data), SocketFlags.None);
}
///
/// 离开游戏
///
///
///
async static Task LeaveGame(Socket sock)
{
var msg = new CS_MD_LeaveRoom() { };
var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsMdLeaveRoom, IMsg2Bytes(msg)));
await sock.SendAsync(new ArraySegment(data), SocketFlags.None);
}
#region 消息收发
static byte[] IMsg2Bytes(pb::IMessage msg)
{
using var ms = new MemoryStream();
using var goutstream = new pb::CodedOutputStream(ms);
msg.WriteTo(goutstream);
goutstream.Flush();
ms.Seek(0, SeekOrigin.Begin);
return ms.ToArray();
}
static async void Dispatch()
{
while (true)
{
var msg = await recvDataBuffer.Reader.ReadAsync();
if (callbacks.ContainsKey(msg._protocallType))
{
callbacks[msg._protocallType](msg);
}
else
{
// 未找到消息处理逻辑
Console.WriteLine("未识别的消息类型:" + msg._protocallType.ToString());
}
}
Console.WriteLine("dispatch 已退出");
}
///
/// 向客户端写入消息
///
static async void WriteToserver(Socket Sock)
{
while (true)
{
var msg = await sendDataBuffer.Reader.ReadAsync();
var data = SocketDataToBytes(msg);
await Sock.SendAsync(new ArraySegment(data), SocketFlags.None);
}
}
///
/// 网络结构转数据
///
///
///
static private byte[] SocketDataToBytes(sSocketData tmpSocketData)
{
byte[] _tmpBuff = new byte[tmpSocketData._buffLength];
byte[] _tmpBuffLength = BitConverter.GetBytes(tmpSocketData._buffLength);
byte[] _tmpDataLenght = BitConverter.GetBytes((UInt16)tmpSocketData._protocallType);
Array.Copy(_tmpBuffLength, 0, _tmpBuff, 0, Constants.HEAD_DATA_LEN);//缓存总长度
Array.Copy(_tmpDataLenght, 0, _tmpBuff, Constants.HEAD_DATA_LEN, Constants.HEAD_TYPE_LEN);//协议类型
Array.Copy(tmpSocketData._data, 0, _tmpBuff, Constants.HEAD_LEN, tmpSocketData._dataLength);//协议数据
return _tmpBuff;
}
///
/// 数据转网络结构
///
///
///
///
static private sSocketData BytesToSocketData(eProtocalCommand _protocalType, byte[] _data)
{
sSocketData tmpSocketData = new sSocketData();
tmpSocketData._buffLength = Constants.HEAD_LEN + _data.Length;
tmpSocketData._dataLength = _data.Length;
tmpSocketData._protocallType = _protocalType;
tmpSocketData._data = _data;
return tmpSocketData;
}
///
/// 接收buffer
///
static private Channel recvDataBuffer = Channel.CreateUnbounded();
///
/// 发送buffer
///
static private Channel sendDataBuffer = Channel.CreateUnbounded();
///
/// 接收客户端发来的信息,客户端套接字对象
///
///
static async void recv(Socket socketServer)
{
socketServer.ReceiveTimeout = 800; // 接收等待超时时间设为800毫秒
var _databuffer = new DataBuffer();
byte[] arrServerRecMsg = new byte[4096]; // 创建一个内存缓冲区,其大小为4k字节
while (true)
{
try
{
var length = await socketServer.ReceiveAsync(new ArraySegment(arrServerRecMsg), SocketFlags.None); // 将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
if (length <= 0) // 视为客户端已经close连接
{
break;
}
_databuffer.AddBuffer(arrServerRecMsg, length); //将收到的数据添加到缓存器中
while (_databuffer.GetData(out sSocketData _socketData)) //取出一条完整数据
{
Console.WriteLine("recv: " + _socketData._protocallType);
await recvDataBuffer.Writer.WriteAsync(_socketData); // 放入channel
}
Array.Clear(arrServerRecMsg, 0, length);
}
catch (SocketException e)
{
if (e.ErrorCode == 10060) // 超时的时候错误号码是10060
{
continue; // 继续等待
}
break;
}
catch (Exception)
{
break;
}
}
Console.WriteLine("recv 已退出");
socketServer.Close(); // 关闭之前accept出来的和客户端进行通信的套接字
}
#endregion
}
}