IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 《Unity3D网络游戏实战》第4章 -> 正文阅读

[游戏开发]《Unity3D网络游戏实战》第4章

TCP数据流

系统缓冲流

收到对端数据时,操作系统会将数据放入Socket的接收缓冲区中。

Socket的Receive方法只是提取接收缓冲区数据,接收缓冲区数据为空时,Receive会阻塞,直到里面有数据。

Socket的Send方法只是将数据写入到发送缓冲区,具体发送由操作系统负责。发送缓冲区数据满了,Send会阻塞。

粘包半包现象

发送端快速发送多条数据,接收端没有及时调用Receive,数据就会在接收端缓冲区累积。

发送端发送的数据还有可能被拆分。

接收和发送并不是一一对应。

解决粘包问题

长度信息法

长度信息+数据包。接收一次完整数据后(长度信息+数据包),再接收下一次数据。

固定长度法

收发固定长度数据,不足增加填充字符。

结束符号法

规定结束符号,作为消息分隔符。

解决粘包代码

发送数据

public void Send(string sendStr) {
	//组装协议
	byte[] bodyBytes = System.Text.Encoding.Default.GetBytes(sendStr);
	Int16 len = (Int16)bodyBytes.Length;
	byte[] lenBytes = BitConverter.GetBytes(len);
	byte[] sendBytes = lenBytes.Concat(bodyBytes).ToArray(); //Concat, using System.Linq;
	socket.Send(sendBytes);
}

接收数据

//接收缓冲区
byte[] readBuff = new byte[1024];
//接收缓冲区的数据长度
int buffCount = 0;

socket.BeginReceive(
	readBuff,//缓冲区
	buffCount,//开始位置
	1024-buffCount,//最多读取多少数据
	0,//标志位
	ReceiveCallback,//回调函数
	socket//状态
);
public void ReceiveCallback(IAsyncResult ar){
	Socket socket = (Socket) ar.AsyncState;
	//获取接收数据长度
	int count = socket.EndReceive(ar);
	buffCount += count;
	//******
}

处理数据

  1. 缓冲区长度小于等于2
public void OnReceiveData(){
	if(buffCount <= 2) 
		return;
	//******
}
  1. 缓冲区长度小于一条完整消息(长度+数据包)
public void OnReceiveData(){
	if(buffCount <= 2) 
		return;
	Int16 bodyLength = BitCoverter.ToInt16(readBuff, 0);
	//消息体长度
	if(buffCount <= 2+bodyLength) 
		return;
	//******
}
  1. 缓冲区长度大于等于一条完整消息(长度+数据包)
public static void Copy(
	Array sourceArray,
	long sourceIndex,
	Array destinationArray,
	long destinationIndex,
	long length
)
public void OnReceiveData(){
	//消息长度
	if(buffCount <= 2) 
		return;
	Int16 bodyLength = BitCoverter.ToInt16(readBuff, 0);
	//消息体长度
	if(buffCount <= 2+bodyLength) 
		return;
	string s = System.Text.Encoding.Default.GetString(readBuff, 2, buffCount);
	//更新缓冲区
	int start = 2+bodyLength;
	int count = buffCount-start;
	Array.Copy(readBuff, start, readBuff, 0, count);
	buffCount -= start;
	//继续读取消息
	if(readBuff.length > 2) 
		OnReceiveData();
}

完整示例

AsyncEchoServer.cs

using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;

namespace AsyncEchoServer {
	
	class ClientState {
		public Socket socket = null;
		public byte[] readBuff = new byte[1024];
	}
	
	class MainClass {
		
		static Socket listenfd;
		static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
		
		public static void SendCallback(IAsyncResult ar) {
			try {
				Socket clientfd = (Socket) ar.AsyncState;
				int count = clientfd.EndSend(ar);
				Console.WriteLine("Socket Send Success");
				
			} catch(SocketException ex) {
				Console.WriteLine("Socket Send Fail" + ex.ToString());
			}
		}
		
		public static void ReceiveCallback(IAsyncResult ar) {
			try {
				ClientState state = (ClientState) ar.AsyncState;
				Socket clientfd = state.socket;
				int count = clientfd.EndReceive(ar);
				Console.WriteLine("Socket Receive Success");
				
				if(count==0) {
					clientfd.Close();
					clients.Remove(clientfd);
					Console.WriteLine("Socket Close");
					return;
				}
				
				//显示
				string recvStr = System.Text.Encoding.Default.GetString(state.readBuff, 2, count-2);
				Console.WriteLine("Receive"+recvStr);
				
				byte[] sendBytes = new byte[count];
				Array.Copy(state.readBuff, 0, sendBytes, 0, count);

				//回显
				clientfd.BeginSend(sendBytes, 0, count, 0, SendCallback, clientfd);
				
				/*
				//广播
				foreach(ClientState s in clients.Values) {
					if(s.socket!=clientfd){
						s.socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallback, s.socket);
					}
				}
				*/
				
				clientfd.BeginReceive(state.readBuff, 0, 1024, 0, ReceiveCallback, state);
			} catch(SocketException ex) {
				Console.WriteLine("Socket Receive Fail" + ex.ToString());
			}
		}
		
		public static void AcceptCallback(IAsyncResult ar) {
			try {
				Console.WriteLine("[服务器]Accept");
				Socket listenfd = (Socket) ar.AsyncState;
				Socket clientfd = listenfd.EndAccept(ar);
				Console.WriteLine("Socket Accept Success");
				
				ClientState state = new ClientState();
				state.socket = clientfd;
				clients.Add(clientfd, state);
		
				clientfd.BeginReceive(state.readBuff, 0, 1024, 0, ReceiveCallback, state);
				listenfd.BeginAccept(AcceptCallback, listenfd);
			} catch(SocketException ex) {
				Console.WriteLine("Socket Accept Fail" + ex.ToString());
			}
		}
				
		public static void Main(string[] args) {
			//Socket
			listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			
			//Bind
			IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
			IPEndPoint ipEp = new IPEndPoint(ipAdr, 8888);
			listenfd.Bind(ipEp);
			
			//Listen
			listenfd.Listen(0);
			
			Console.WriteLine("[服务器]启动成功");
			
			//Accept
			listenfd.BeginAccept(AcceptCallback, listenfd);
			
			//Wait
			Console.ReadLine();
				
			//Close
			listenfd.Close();
		}
		
	}
	
}
csc AsyncEchoServer.cs
AsyncEchoServer

AsyncEchoClient.cs

using System;
using System.Net.Sockets;
using System.Linq;
using System.Threading;

namespace AsyncEchoClient {
	class MainClass {
		static Socket socket;
		//接收缓冲区
		static byte[] readBuff = new byte[1024];
		//接收缓冲区数据长度
		static int buffCount = 0;
		//接收文字
		static string recvStr;
		
		public static void Connect() {
			//Socket
			socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
					
			//Connect
			socket.BeginConnect("127.0.0.1", 8888, ConnectCallback, socket);
		}
		
		public static void ConnectCallback(IAsyncResult ar) {
			try {
				Socket socket = (Socket) ar.AsyncState;
				socket.EndConnect(ar);
				//Console.WriteLine("Socket Connect Success");
				
				socket.BeginReceive(readBuff, buffCount, 1024-buffCount, 0, ReceiveCallback, socket);
			} catch(SocketException ex) {
				Console.WriteLine("Socket Connect Fail" + ex.ToString());
			}
		}
		
		public static void ReceiveCallback(IAsyncResult ar) {
			try {
				Socket socket = (Socket) ar.AsyncState;
				//获取接收数据长度
				int count = socket.EndReceive(ar);
				//Console.WriteLine("Socket Receive Success");
				buffCount += count;
				//处理二进制消息
				OnReceiveData();
				
				//等待,模拟粘包
				Thread.Sleep(1000);
				
				//recvStr = System.Text.Encoding.Default.GetString(readBuff, 0, count);
				//Console.WriteLine("[客户端接收]"+recvStr);
		
				//继续接收数据
				socket.BeginReceive(readBuff, buffCount, 1024-buffCount, 0, ReceiveCallback, socket);
			} catch(SocketException ex) {
				Console.WriteLine("Socket Receive Fail" + ex.ToString());
			}
		}
		
		public static void OnReceiveData() {
			//Console.WriteLine("[Recv 1 buffCount=]" + buffCount);
			//Console.WriteLine("[Recv 2 readBuff=]" + BitConverter.ToString(readBuff));
			
			//消息长度
			if(buffCount <= 2) 
				return;
			
			//消息体长度
			Int16 bodyLength = BitConverter.ToInt16(readBuff, 0);
			//Console.WriteLine("[Recv 3 bodyLength=]" + bodyLength);
			
			if(buffCount <= 2+bodyLength) 
				return;
			
			string s = System.Text.Encoding.Default.GetString(readBuff, 2, buffCount);
			//Console.WriteLine("[Recv 4 s=]" + s);
			recvStr = s + "\n" + recvStr;
			
			//更新缓冲区
			int start = 2+bodyLength;
			int count = buffCount-start;
			Array.Copy(readBuff, start, readBuff, 0, count);
			buffCount -= start;
			//Console.WriteLine("[Recv 5 buffCount=]" + buffCount);
			
			//继续读取消息
			//if(readBuff.length > 2) 
			OnReceiveData();
		}
		
		public static void Send(string sendStr) {
			//组装协议
			byte[] bodyBytes = System.Text.Encoding.Default.GetBytes(sendStr);
			Int16 len = (Int16)bodyBytes.Length;
			byte[] lenBytes = BitConverter.GetBytes(len);
			byte[] sendBytes = lenBytes.Concat(bodyBytes).ToArray(); 
			
			socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallback, socket);
			//Console.WriteLine("[Send]" + BitConverter.ToString(sendBytes));
		}
		
		public static void SendCallback(IAsyncResult ar) {
			try {
				Socket socket = (Socket) ar.AsyncState;
				int count = socket.EndSend(ar);
				//Console.WriteLine("Socket Send Success");
				
			} catch(SocketException ex) {
				Console.WriteLine("Socket Send Fail" + ex.ToString());
			}
		}

		public static void Main(string[] args) {
			Connect();
		
			while(true) {
				string sendStr = Console.ReadLine();
				if(sendStr.Length==0)
					continue;
				else if(sendStr=="quit")
					break;
				Send(sendStr);
				
				Console.Clear();
				Console.WriteLine(recvStr);
			}
			
			//Close
			socket.Close();
		}
	}
}
csc AsyncEchoClient.cs
AsyncEchoClient

大端小端

public static short ToInt16(byte[] value, int startIndex) {
	if(startIndex%2==0){//data is aligned
		return *((short*)pbyte);
	}else{
		if(IsLittleEndian) {
			return (short)((*pbyte)|(*(pbyte+1)<<8));
		} else {
			return (short)((*pbyte<<8)|(*(pbyte+1)));
		}
	}
}

区分

数据0x0102

模式低地址高地址
大端模式0102
小端模式0201

Reverse函数

if(!BitConverter.IsLittleEndian) {
	lenBytes = lenBytes.Reverse();
}

手动还原数值

Int16 bodyLength = (short)((readBuff[1]<<8)|readBuff[0]);

完整收发数据

Queue

Queue<ByteArray> writeQueue = new Queue<ByteArray>();
ByteArray ba = new ByteArray(sendBytes);

//放入队列末尾
writeQueue.Enqueue(ba);

//获取首端元素,队列不变
ByteArray ba2 = writeQueue.First();

//弹出队列首端
ba2 = writeQueue.Dequeue();

采用队列的原因是队列的入队(Enqueue)和出队(Dequeue)的时间复杂度是o(1),对于lock执行时间短,可以最大限度地减少程序等待的时间。

ByteArray

ByteArray.cs

using System;

public class ByteArray  {
	//默认大小
	const int DEFAULT_SIZE = 1024;
	//初始大小
	int initSize = 0;
	//缓冲区
	public byte[] bytes;
	//读写位置
	public int readIdx = 0;
	public int writeIdx = 0;
	//容量
	private int capacity = 0;
	//剩余空间
	public int remain { get { return capacity-writeIdx; }}
	//数据长度
	public int length { get { return writeIdx-readIdx; }}

	//构造函数
	public ByteArray(int size = DEFAULT_SIZE){
		bytes = new byte[size];
		capacity = size;
		initSize = size;
		readIdx = 0;
		writeIdx = 0;
	}

	//构造函数
	public ByteArray(byte[] defaultBytes){
		bytes = defaultBytes;
		capacity = defaultBytes.Length;
		initSize = defaultBytes.Length;
		readIdx = 0;
		writeIdx = defaultBytes.Length;
	}

	//重设尺寸
	public void ReSize(int size){
		if(size < length || size < initSize)
			return;
		
		capacity = 1;
		while(capacity<size) 
			capacity *= 2;
		
		byte[] newBytes = new byte[capacity];
		Array.Copy(bytes, readIdx, newBytes, 0, length);
		bytes = newBytes;
		
		writeIdx = length;
		readIdx = 0;
	}

	//检查并移动数据
	public void CheckAndMoveBytes(){
		if(length < 8){
			MoveBytes();
		}
	}

	//移动数据
	public void MoveBytes(){
		if(length>0) {
			Array.Copy(bytes, readIdx, bytes, 0, length);
		}
		writeIdx = length;
		readIdx = 0;
	}

	//写入数据
	public int Write(byte[] bs, int offset, int count){
		if(remain < count){
			ReSize(length + count);
		}
		Array.Copy(bs, offset, bytes, writeIdx, count);
		writeIdx += count;
		return count;
	}

	//读取数据
	public int Read(byte[] bs, int offset, int count){
		count = Math.Min(count, length);
		Array.Copy(bytes, readIdx, bs, offset, count);
		readIdx += count;
		CheckAndMoveBytes();
		return count;
	}
	
	//读取Int16
	public Int16 ReadInt16(){
		if(length < 2) 
			return 0;
		Int16 ret = BitConverter.ToInt16(bytes, readIdx);
		readIdx += 2;
		CheckAndMoveBytes();
		return ret;
	}

	//读取Int32
	public Int32 ReadInt32(){
		if(length < 4) 
			return 0;
		Int32 ret = BitConverter.ToInt32(bytes, readIdx);
		readIdx += 4;
		CheckAndMoveBytes();
		return ret;
	}

	//打印缓冲区(仅为调试)
	public override string ToString(){
		return BitConverter.ToString(bytes, readIdx, length);
	}

	//打印调试信息(仅为调试)
	public string Debug(){
		return string.Format("readIdx({0}) writeIdx({1}) bytes({2})",
			readIdx,
			writeIdx,
			BitConverter.ToString(bytes, 0, capacity)
		);
	}
}

TestByteArray.cs

using System.Collections;
using System.Collections.Generic;
using System;

public class TestByteArray {
	public static void Main(string[] args) {
		//[1 创建]
		ByteArray buff = new ByteArray(8);
		Console.WriteLine("[1 debug ]->" + buff.Debug());
		Console.WriteLine("[1 string]->" + buff.ToString());
		
		//[2 write]
		byte[] wb = new byte[]{1,2,3,4,5};
		buff.Write(wb, 0, 5);
		Console.WriteLine("[2 debug ]->" + buff.Debug());
		Console.WriteLine("[2 string]->" + buff.ToString());
		
		//[3 read]
		byte[] rb = new byte[4];
		buff.Read(rb, 0, 2);
		Console.WriteLine("[3 debug ]->" + buff.Debug());
		Console.WriteLine("[3 string]->" + buff.ToString());
		Console.WriteLine("[3 rb    ]->" + BitConverter.ToString(rb));
		
		//[4 write, resize]
		wb = new byte[]{6,7,8,9,10,11};
		buff.Write(wb, 0, 6);
		Console.WriteLine("[4 debug ]->" + buff.Debug());
		Console.WriteLine("[4 string]->" + buff.ToString());
	}
}
csc TestByteArray.cs ByteArray.cs 
TestByteArray

ByteArray异步回显程序

ByteArrayAsyncEchoServer.cs

using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Linq;

namespace ByteArrayAsyncEchoServer
{
	
	class ClientState {
		public Socket socket = null;
		//接收缓冲区
		public ByteArray readBuff = new ByteArray();
		//发送缓冲区
		public Queue<ByteArray> writeQueue = new Queue<ByteArray>();
	}
	
	class MainClass {
		
		static Socket listenfd;
		static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
		
		public static void ReceiveCallback(IAsyncResult ar) {
			try {
				ClientState state = (ClientState) ar.AsyncState;
				Socket clientfd = state.socket;
				int count = clientfd.EndReceive(ar);
				state.readBuff.writeIdx += count;
				
				if (count==0) {
					clientfd.Close();
					clients.Remove(clientfd);
					Console.WriteLine("Socket Close");
					return;
				}
				
				//处理二进制消息
				OnReceiveData(state);

				//继续接收数据
				state.readBuff.CheckAndMoveBytes();
				/*
				if(state.readBuff.remain<8) {
					state.readBuff.MoveBytes();
					state.readBuff.ReSize(state.readBuff.length*2);
				}*/
				state.socket.BeginReceive(state.readBuff.bytes, state.readBuff.writeIdx, state.readBuff.remain, 0, ReceiveCallback, state);

			}
			catch (SocketException ex) {
				Console.WriteLine("Socket Receive Fail" + ex.ToString());
			}
		}
		public static void OnReceiveData(ClientState state)
		{
			Console.WriteLine("[接收 1] length = " + state.readBuff.length);
			Console.WriteLine("[接收 2] readBuff = " + state.readBuff.ToString());

			if (state.readBuff.length <= 2)
				return;

			int readIdx = state.readBuff.readIdx;
			byte[] bytes = state.readBuff.bytes;

			//消息体长度
			//Int16 bodyLength = BitConverter.ToInt16(bytes, readIdx);
			Int16 bodyLength = (Int16)((bytes[readIdx + 1] << 8) | (bytes[readIdx]));

			if (state.readBuff.length < 2 + bodyLength)
				return;
			state.readBuff.readIdx += 2;
			Console.WriteLine("[接收 3] bodyLength = " + bodyLength);

			//消息体
			byte[] stringByte = new byte[bodyLength];
			state.readBuff.Read(stringByte, 0, bodyLength);
			string s = System.Text.Encoding.Default.GetString(stringByte);
			Console.WriteLine("[接收 4] s = " + s);
			Console.WriteLine("[接收 5] readBuff = " + state.readBuff.ToString());

			Send(s, state);

			//继续读取消息
			//if(state.readBuff.length > 2) 
			OnReceiveData(state);
		}

		public static void Send(string sendStr, ClientState state)
		{
			//组装协议
			byte[] bodyBytes = System.Text.Encoding.Default.GetBytes(sendStr);
			Int16 len = (Int16)bodyBytes.Length;
			byte[] lenBytes = BitConverter.GetBytes(len);
			byte[] sendBytes = lenBytes.Concat(bodyBytes).ToArray();

			ByteArray ba = new ByteArray(sendBytes);
			int count;
			lock (state.writeQueue)
			{
				state.writeQueue.Enqueue(ba);
				count = state.writeQueue.Count;
			}
			if (count == 1)
				state.socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallback, state);

			Console.WriteLine("[Send]" + BitConverter.ToString(sendBytes));
		}

		public static void SendCallback(IAsyncResult ar)
		{
			ClientState state = (ClientState)ar.AsyncState;
			Socket socket = state.socket;
			int count = socket.EndSend(ar);

			ByteArray ba;
			lock (state.writeQueue)
			{
				ba = state.writeQueue.First();
			}
			
			ba.readIdx += count;
			if (ba.length == 0){
				lock (state.writeQueue){
					state.writeQueue.Dequeue();
				}

			} else {
				socket.BeginSend(ba.bytes, ba.readIdx, ba.length, 0, SendCallback, state);
			}
		}

		public static void AcceptCallback(IAsyncResult ar) {
			try {
				Socket listenfd = (Socket) ar.AsyncState;
				Socket clientfd = listenfd.EndAccept(ar);
				
				ClientState state = new ClientState();
				state.socket = clientfd;
				clients.Add(clientfd, state);
		
				clientfd.BeginReceive(state.readBuff.bytes, state.readBuff.writeIdx, state.readBuff.remain, 0, ReceiveCallback, state);

				listenfd.BeginAccept(AcceptCallback, listenfd);
			} catch(SocketException ex) {
				Console.WriteLine("Socket Accept Fail" + ex.ToString());
			}
		}
				
		public static void Main(string[] args) {
			//Socket
			listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			
			//Bind
			IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
			IPEndPoint ipEp = new IPEndPoint(ipAdr, 8888);
			listenfd.Bind(ipEp);
			
			//Listen
			listenfd.Listen(0);
			
			Console.WriteLine("[服务器]启动成功");
			
			//Accept
			listenfd.BeginAccept(AcceptCallback, listenfd);
			
			//Wait
			Console.ReadLine();
				
			//Close
			listenfd.Close();
		}
		
	}
	
}
csc ByteArrayAsyncEchoServer.cs ByteArray.cs
ByteArrayAsyncEchoServer

ByteArrayAsyncEchoClient.cs

using System;
using System.Net.Sockets;
using System.Linq;
using System.Collections.Generic;

namespace ByteArrayAsyncEchoClient {
	class MainClass {
		static Socket socket;
		//发送缓冲区
		static Queue<ByteArray> writeQueue = new Queue<ByteArray>();
		//接收缓冲区
		static ByteArray readBuff = new ByteArray();
		
		public static void Connect() {
			//Socket
			socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
					
			//Connect
			socket.BeginConnect("127.0.0.1", 8888, ConnectCallback, socket);
		}
		
		public static void ConnectCallback(IAsyncResult ar) {
			Socket socket = (Socket) ar.AsyncState;
			socket.EndConnect(ar);
				
			socket.BeginReceive(readBuff.bytes, readBuff.writeIdx, readBuff.remain, 0, ReceiveCallback, socket);
		}
		
		public static void ReceiveCallback(IAsyncResult ar) {
			Socket socket = (Socket) ar.AsyncState;
			//获取接收数据长度
			int count = socket.EndReceive(ar);
			readBuff.writeIdx += count;

			//处理二进制消息
			OnReceiveData();

			//继续接收数据
			//readBuff.CheckAndMoveBytes();
			if(readBuff.remain<8) {
				readBuff.MoveBytes();
				readBuff.ReSize(readBuff.length*2);
			}
			socket.BeginReceive(readBuff.bytes, readBuff.writeIdx, readBuff.remain, 0, ReceiveCallback, socket);
		}
		
		public static void OnReceiveData() {
			Console.WriteLine("[接收 1] length = " + readBuff.length);
			Console.WriteLine("[接收 2] readBuff = " + readBuff.ToString());

			if (readBuff.length <= 2) 
				return;

			int readIdx = readBuff.readIdx;
			byte[] bytes = readBuff.bytes;

			//消息体长度
			//Int16 bodyLength = BitConverter.ToInt16(bytes, readIdx);
			Int16 bodyLength = (Int16)((bytes[readIdx+1]<<8)|(bytes[readIdx]));

			if (readBuff.length < 2+bodyLength) 
				return;
			readBuff.readIdx += 2;
			Console.WriteLine("[接收 3] bodyLength = " + bodyLength);

			//消息体
			byte[] stringByte = new byte[bodyLength];
			readBuff.Read(stringByte, 0, bodyLength);
			string s = System.Text.Encoding.Default.GetString(stringByte);
			Console.WriteLine("[接收 4] s = " + s);
			Console.WriteLine("[接收 5] readBuff = " + readBuff.ToString());

			//继续读取消息
			//if(readBuff.length > 2) 
			OnReceiveData();
		}
		
		public static void Send(string sendStr) {
			//组装协议
			byte[] bodyBytes = System.Text.Encoding.Default.GetBytes(sendStr);
			Int16 len = (Int16)bodyBytes.Length;
			byte[] lenBytes = BitConverter.GetBytes(len);
			byte[] sendBytes = lenBytes.Concat(bodyBytes).ToArray();
			
			ByteArray ba = new ByteArray(sendBytes);
			int count;
			lock(writeQueue) {
				writeQueue.Enqueue(ba);
				count = writeQueue.Count;
			}
			if(count==1)
				socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallback, socket);

			Console.WriteLine("[Send]" + BitConverter.ToString(sendBytes));
		}
		
		public static void SendCallback(IAsyncResult ar) {
			Socket socket = (Socket) ar.AsyncState;
			int count = socket.EndSend(ar);

			ByteArray ba;
			lock (writeQueue) {
				ba = writeQueue.First();
			}

			ba.readIdx += count;
            if (ba.length == 0){
				lock (writeQueue){
					writeQueue.Dequeue();
				}

			} else {
				socket.BeginSend(ba.bytes, ba.readIdx, ba.length, 0, SendCallback, socket);
			}
		}

		public static void Main(string[] args) {
			Connect();
		
			while(true) {
				string sendStr = Console.ReadLine();
				if(sendStr.Length==0)
					continue;
				else if(sendStr=="quit")
					break;
				Send(sendStr);
			}
			
			//Close
			socket.Close();
		}
	}
}
csc ByteArrayAsyncEchoClient.cs ByteArray.cs
ByteArrayAsyncEchoClient
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-01-24 11:15:39  更:2022-01-24 11:17:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 18:27:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码