这是用C#实现的服务端与客户端,Unity中的网络连接功能也是以此为基础的,先理解常规的网络操作,才能在实际应用中游刃有余。
服务端代码,首先新建一个C#控制台项目,下面是一个消息类,这个类是为了应对消息的封装和解析写的,发送端发送消息时可以帮你添加,标记接收后根据对应标记将消息解析出来,当然这个标记可以你自己指定,因此一个专门用于处理消息的类就很有必要。
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
//传输的消息类,给出的格式和解析方法
public class Message
{
#region 字段
private byte[] data = new byte[1024];
private int startIndex = 0; //开始存储的字节所在字节数组中的位置
#endregion
#region 属性
public byte[] Data
{
get { return data; }
}
public int StartIndex
{
get { return startIndex; }
}
//当前字节数组中剩余的可存储空间
public int RemainLength
{
get { return data.Length - startIndex; }
}
#endregion
#region 方法
///
/// 更新存储字节索引,数量增加
///
public void AddCount(int count)
{
startIndex += count;
}
#endregion
///
/// 读取(解析)客户端发送过来的数据
///
public void ReadMessage()
{
while (true)
{
//当发送过来的一条数据长度小于四位即没有数据头时
if (startIndex < 4) return;
//获取数据总长度
int count = BitConverter.ToInt32(data, 0);
//按数据头逐步解析每个字节数组
if ((startIndex - 4) >= count)
{
Console.WriteLine("总长度:" + startIndex + " 当前包的长度" + count);
string s = Encoding.UTF8.GetString(data, 4, count);
Console.WriteLine("该包中的数据:" + s);
//未解析的数据前移
Array.Copy(data, count + 4, data, 0, startIndex - count - 4);
startIndex -= (4 + count);
}
else
{
break;
}
}
}
}
第二步就是编写服务端,这个服务端采用异步收发处理消息机制,即可以打开多个客户端与其连接,服务端需要创建客户端的映射,就好比你想寄一件快递,你只需给快递站你想要寄到目的地地址,但快递站最终是需要所有的寄件人和收件人地址的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace TCP服务端
{
class Program
{
#region 字段
//服务端接收到的数据
private static byte[] dataBuffer = new byte[1024];
//消息处理类
private static Message m_Message = new Message();
#endregion
#region 方法
//执行程序入口
static void Main(string[] args)
{
StartServerAsync();
Console.ReadKey();
}
///
/// 服务端异步客户端
///
static void StartServerAsync()
{
//新建服务端Socket
//AddressFamily.InterNetwork IP4类型的网络地址
//SocketType.Stream 使用流传输
//ProtocolType.Tcp 使用TCP协议
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获取本地IP地址
IPAddress ipAdress = IPAddress.Parse("127.0.0.1");
//指定访问点,Ip地址与端口号
IPEndPoint ipEndPoint = new IPEndPoint(ipAdress, 6890);
//服务端绑定访问点
serverSocket.Bind(ipEndPoint);
//服务端监听该端口,并设置等待队列最大长度
serverSocket.Listen(10);
//有客户端访问该服务端(异步)
serverSocket.BeginAccept(AcceptCallBack, serverSocket);
}
#endregion
#region 回调事件
///
/// 服务端异步接收客户端连接
///
static void AcceptCallBack(IAsyncResult asyncResoult)
{
Socket serverSocket = asyncResoult.AsyncState as Socket;
//获取一个连接的客户端,结束接收
Socket clientSocket = serverSocket.EndAccept(asyncResoult);
//向客户端发送消息
string str = "Hellow client, I am server. 你好客户端,我是服务端";
byte[] bytStr = Encoding.UTF8.GetBytes(str);
clientSocket.Send(bytStr);
//服务端接收客户端发送过来的消息(异步)
clientSocket.BeginReceive(
m_Message.Data,
m_Message.StartIndex,
m_Message.RemainLength,
SocketFlags.None,
RecevieCallBack, clientSocket);
//再次开启接收客户端
serverSocket.BeginAccept(AcceptCallBack, serverSocket);
}
///
/// 服务端异步获取客户端发送的消息
///
static void RecevieCallBack(IAsyncResult asyncResoult)
{
Socket clientSocket = null;
try
{
clientSocket = asyncResoult.AsyncState as Socket;
int count = clientSocket.EndReceive(asyncResoult);
//当客户端发送消息为空时
if (count == 0)
{
clientSocket.Close();
return;
}
//消息中字节存储数量及索引增加
m_Message.AddCount(count);
string s = Encoding.UTF8.GetString(m_Message.Data, 0, count);
m_Message.ReadMessage();
Console.WriteLine("接收客户端传递过来的数据:" + s + ",");
//再次开启异步接收(回调)
//服务端接收客户端发送过来的消息(异步)
clientSocket.BeginReceive(
m_Message.Data,
m_Message.StartIndex,
m_Message.RemainLength,
SocketFlags.None,
RecevieCallBack, clientSocket);
}
catch (Exception e)
{
Console.WriteLine(e);
clientSocket.Close();
}
//结束接收数据
}
#endregion
}
}
接下来就是客户端了,这时再新建一个C#控制台项目,首先还是先建立一个消息类,只是这个消息类只要实现消息的打包就行,即将字符串转化成字节数组,毕竟流传输传的是字节流。
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
public class Message
{
public static byte[] GetBytes(string str)
{
byte[] data = Encoding.UTF8.GetBytes(str);
//获取字节长度
int dataLength = data.Length;
//将数据字节长度转化为字节数组
byte[] lengthBuffer = BitConverter.GetBytes(dataLength);
//数据字节长度与数据粘合在一起
byte[] allData = lengthBuffer.Concat(data).ToArray();
return allData;
}
}
最后就是客户端了,相比于服务端要简单得多。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace TCP客户端
{
class Program
{
static void Main(string[] args)
{
//创建客户端Socket
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//远程连接的终点Ip地址
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6890);
//连接服务端的Ip地址和端口
clientSocket.Connect(ipEndPoint);
//接收服务端的消息
byte[] buffer = new byte[1024];
int count = clientSocket.Receive(buffer);
string bufferStr = Encoding.UTF8.GetString(buffer, 0, count);
Console.WriteLine("服务端发送过来的消息:" + bufferStr);
for (int i = 0; i < 100; i++)
{
clientSocket.Send(Message.GetBytes(i.ToString()));
}
Console.ReadKey();
clientSocket.Close();
}
}
}
这两个项目编译生成后先打开服务端项目下bin/Debug/中的exe,再打开客户端的exe文件,当然由于这里可以异步传输,故可以打开多个客户端,然而只能在你电脑上实现连接,因为绑定的IP是你的本地IP,要实现多台电脑互联,还需要对服务端和客户端的IP地址进行设置。