关于socket类的更多了解:https://msdn.microsoft.com/zh-cn/library/System.Net.Sockets.Socket(v=vs.110).aspx
要发送字节数组封装类
现在的功能只是发送字符串,也可以改造成传输更多数据类型的类
using System;
using System.Net.Sockets;
//为了避免粘包半包情况
//这个类用来封装字节流,主要分为header+body,header:记录信息包的长度,body:要发送的信息
//TCP每次先读取流中的4个字节,了解到这条信息的长度后,读取同长度的字节流
public class XHNetBits
{
public Socket handlerSocket;
private byte[] _bytes;
public byte[] bytes
{
get { return _bytes; }
}
private int MAX_LEN = 1024;
//body的长度
public int bodyLen
{
get
{
int bodyLen = BitConverter.ToInt32(_bytes, 0);
return bodyLen;
}
}
public const int HEAD_LEN = 4;
private int _currentBodyLen = 0;
public XHNetBits()
{
_bytes = new byte[MAX_LEN];
}
//传入字节数组,直接形成header+body字节数组
public XHNetBits(byte[] bs)
{
_bytes = new byte[HEAD_LEN + bs.Length];
byte[] headBs = BitConverter.GetBytes(bs.Length);
headBs.CopyTo(_bytes, 0);
bs.CopyTo(_bytes, HEAD_LEN);
}
public void WriteUShort(ushort number)
{
byte[] bs = System.BitConverter.GetBytes(number);
if (bs.Length + _currentBodyLen > MAX_LEN)
{
return;
}
bs.CopyTo(_bytes, HEAD_LEN + _currentBodyLen);
_currentBodyLen += bs.Length;
}
public void WriteStream(string str)
{
int len = System.Text.UTF8Encoding.UTF8.GetByteCount(str);
System.Text.UTF8Encoding.UTF8.GetBytes(str, 0, str.Length, _bytes, HEAD_LEN + _currentBodyLen);
_currentBodyLen += len;
}
public ushort ReadUshort()
{
ushort len = System.BitConverter.ToUInt16(_bytes, 0);
return len;
}
public string ReadString()
{
ushort len = ReadUshort();
string s = System.Text.UTF8Encoding.UTF8.GetString(_bytes, HEAD_LEN, len);
return s;
}
}
unity客户端类:
挂在如图ui上
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Net.Sockets;
using System.Net;
public class MyChatClient : MonoBehaviour
{
private InputField _input;
private Button _btn;
public Text _msg;
MyTCPClient _tcpClient;
public string msg;
public static MyChatClient Instance = null;
void Awake()
{
if (Instance == null)
Instance = this;
}
void Update()
{
_msg.text = msg;
}
void Start()
{
_input = transform.FindChild("input").GetComponent<InputField>();
_btn = transform.FindChild("send").GetComponent<Button>();
_msg = transform.FindChild("msg").GetComponent<Text>();
_btn.onClick.AddListener(delegate() { OnSend(); });
_tcpClient = new MyTCPClient();
_tcpClient.Connect("127.0.0.1", 10001);
_msg.text = "msg";
}
public void OnSend()
{
string msg = _input.text;
_tcpClient.Send(msg);
}
public class MyTCPClient
{
private Socket _socket = null;
//连接服务器
public bool Connect(string ip, int port)
{
IPAddress address = IPAddress.Parse(ip);
IPEndPoint endP = new IPEndPoint(address, port);
try
{
while (true)
{
_socket = new Socket(endP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
//异步方法,连接上后调用ConnectionCallback
_socket.BeginConnect(endP, new System.AsyncCallback(ConnectionCallback), _socket);
break;
}
}
catch (System.Exception e)
{
Debug.LogError(e);
return false;
}
return true;
}
private void ConnectionCallback(System.IAsyncResult asy)
{
Debug.Log("c b");
Socket handlerSocket = (Socket)asy.AsyncState;
//完成连接服务器
handlerSocket.EndConnect(asy);
handlerSocket.SendTimeout = 3;
handlerSocket.ReceiveTimeout = 3;
XHNetBits netBits = new XHNetBits();
netBits.handlerSocket = handlerSocket;
//开始接收四个字节,这四个字节是int,是这个信息流的长度
_socket.BeginReceive(
netBits.bytes,
0,
XHNetBits.HEAD_LEN,
SocketFlags.None,
new System.AsyncCallback(ReceiveHeader),
netBits
);
}
//以下使用ReceiveHeader和ReceiveBody连个方法循环读取流,
//在TCP中,客户端和监听端的发送和接收不一定对应,TCP的传输是流的概念,不是发送次数,所以尽管读取流
private void ReceiveHeader(System.IAsyncResult result)
{
XHNetBits netBits = (XHNetBits)result.AsyncState;
try
{
int read = netBits.handlerSocket.EndReceive(result);
if (read < 1)
{
Debug.Log("失去连接");
return;
}
//根据header 描述的长度读取body
netBits.handlerSocket.BeginReceive(
netBits.bytes,
XHNetBits.HEAD_LEN,
XHNetBits.HEAD_LEN + netBits.bodyLen,
SocketFlags.None,
new System.AsyncCallback(ReceviBody),
netBits
);
}
catch (System.Exception e)
{
Debug.Log(e);
}
}
private void ReceviBody(System.IAsyncResult result)
{
XHNetBits netBits = (XHNetBits)result.AsyncState;
try
{
int read = netBits.handlerSocket.EndReceive(result);
if (read < 1)
{
Debug.Log("失去连接");
return;
}
string msg = netBits.ReadString();
Debug.Log("收到消息--------->>" + msg);
MyChatClient.Instance.msg = msg;
//接收完一对header和body后,继续重新等待下一个流的header
netBits.handlerSocket.BeginReceive(
netBits.bytes,
0,
XHNetBits.HEAD_LEN,
SocketFlags.None,
new System.AsyncCallback(ReceiveHeader),
netBits
);
}
catch (System.Exception e)
{
Debug.Log(e);
}
}
//发送消息
public void Send(string msg)
{
if (!_socket.Connected)
{
Debug.LogError("un connect!");
return;
}
byte[] sendBs = System.Text.Encoding.UTF8.GetBytes(msg);
XHNetBits netBs = new XHNetBits(sendBs);
NetworkStream netStream;
lock (_socket)
{
netStream = new NetworkStream(_socket);
}
if (netStream.CanWrite)
{
try
{
netStream.BeginWrite(netBs.bytes, 0, netBs.bytes.Length, new System.AsyncCallback(SendCallback), netStream);
}
catch (System.Exception e)
{
Debug.LogError(e);
}
}
else
{
Debug.Log("can not write");
}
}
private void SendCallback(System.IAsyncResult result)
{
NetworkStream netStream = (NetworkStream)result.AsyncState;
try
{
Debug.Log("send end !");
netStream.EndWrite(result);
netStream.Flush();
netStream.Close();
}
catch (System.Exception e)
{
Debug.LogError(e);
}
}
}
}
服务端:
这个是直接在VS2013上直接新建的控制台应用程序:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace MyChatServer02
{
class Program
{
static void Main(string[] args)
{
ServerSocket s = new ServerSocket("127.0.0.1", 10001);
s.Start();
}
public class ServerSocket {
//先进后出queue,保存消息字符串
private static System.Collections.Queue msgQueue = new System.Collections.Queue();
//客户端连接成功后,保存服务器分配处理各个客户端的socket
private List<Socket> _handlerSockets = new List<Socket>();
//处理消息的线程
private System.Threading.Thread processThread;
private int maxConnection = 100;
//服务端的监听socket
private Socket _listnerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private string ip = null;
private int port;
//构造方法
public ServerSocket(string ip, int port) {
this.ip = ip;
this.port = port;
//开启一个线程,用while等待处理客户端的消息
processThread = new Thread(new ThreadStart(ProcessMsg));
processThread.Start();
}
private void ProcessMsg() {
string msg = null;
while (true) {
if (msgQueue.Count < 1)
continue;
//从queue里获取消息分发给客户端
for (msg = (string)msgQueue.Dequeue(); msg != null; )
{
for (int i = 0; i < _handlerSockets.Count; i++) {
Socket handlerSocket = _handlerSockets[i];
if (handlerSocket.Connected)
{
this.Send(msg, _handlerSockets[i]);
}
else {
_handlerSockets.RemoveAt(i);
Console.WriteLine("移除一个已经下线的客户端handler socket!");
}
}
msg = null;
}
}
}
public void Start(){
Console.WriteLine("start...");
Console.WriteLine("at : " + ip + " : " + port);
IPAddress address = IPAddress.Parse(this.ip);
IPEndPoint localIpEnd = new IPEndPoint(address, this.port);
_listnerSocket.Bind(localIpEnd);
_listnerSocket.Listen(maxConnection);
while (true) {
try
{
//BeginAccept:等待连接,等待一个socket client连接上来
_listnerSocket.BeginAccept(new AsyncCallback(AcceptedClient), _listnerSocket);
break;
}
catch (Exception e)
{
Console.WriteLine("--->" + e);
}
}
}
//IAsyncResult 对象,它存储此异步操作的状态信息以及任何用户定义数据。
private void AcceptedClient(IAsyncResult ar)
{
Console.WriteLine("新连接一个客户端!!");
try {
Socket listener = (Socket)ar.AsyncState;
//结束EndAccept,返回一个 Socket 对象,它处理与远程主机(client)的通信。
Socket handlerSocket = listener.EndAccept(ar);
_handlerSockets.Add(handlerSocket);
handlerSocket.SendTimeout = 3;
handlerSocket.ReceiveTimeout = 3;
XHNetBits netBits = new XHNetBits();
netBits.handlerSocket = handlerSocket;
//开启读取接受字节
handlerSocket.BeginReceive(
netBits.bytes,
0,
XHNetBits.HEAD_LEN,
SocketFlags.None,
new AsyncCallback(ReceiveHeader),
netBits
);
}
catch (Exception e) {
Console.WriteLine(e);
}
_listnerSocket.BeginAccept(new AsyncCallback(AcceptedClient), _listnerSocket);
}
//以下使用ReceiveHeader和ReceiveBody连个方法循环读取流,
//在TCP中,客户端和监听端的发送和接收不一定对应,TCP的传输是流的概念,不是发送次数,所以尽管读取流
private void ReceiveHeader(IAsyncResult result)
{
XHNetBits netBits = (XHNetBits)result.AsyncState;
try
{
int len = netBits.handlerSocket.EndReceive(result);
if (len < 1) {
Console.WriteLine("read len < 1,1用户下线!");
if (_handlerSockets.Contains(netBits.handlerSocket))
{
_handlerSockets.Remove(netBits.handlerSocket);
Console.WriteLine("移除一个已下线的handler socket");
}
return;
}
//接收完一对header和body后,继续重新等待下一个流的header
netBits.handlerSocket.BeginReceive(
netBits.bytes,
XHNetBits.HEAD_LEN,
XHNetBits.HEAD_LEN + netBits.bodyLen,
SocketFlags.None,
new AsyncCallback(ReciveBody),
netBits
);
}
catch (Exception e) {
Console.WriteLine(e);
}
}
//最后又循环ReceiveHeader
private void ReciveBody(IAsyncResult result) {
XHNetBits netBits = (XHNetBits)result.AsyncState;
try
{
int recvlen = netBits.handlerSocket.EndReceive(result);
if (recvlen < 1)
{
Console.WriteLine("body read len < 1, 1用户下线!");
if (_handlerSockets.Contains(netBits.handlerSocket))
{
_handlerSockets.Remove(netBits.handlerSocket);
Console.WriteLine("移除一个已下线的handler socket");
}
}
string body = netBits.ReadString();
msgQueue.Enqueue(body);
Console.WriteLine(body);
//循环开启读取接受字节
//开启读取接受字节
netBits.handlerSocket.BeginReceive(
netBits.bytes,
0,
XHNetBits.HEAD_LEN,
SocketFlags.None,
new AsyncCallback(ReceiveHeader),
netBits
);
}
catch (System.Exception e) {
Console.WriteLine(e);
}
}
private void Send(String msg, Socket handlerSocket) {
if (!handlerSocket.Connected) {
if (_handlerSockets.Contains(handlerSocket))
{
_handlerSockets.Remove(handlerSocket);
Console.WriteLine("移除一个已下线的handler socket");
}
Console.WriteLine("此客户端已经下线");
return;
}
NetworkStream netStream = null;
lock (handlerSocket)
{
netStream = new NetworkStream(handlerSocket);
}
if (netStream.CanWrite) {
byte[] msgBs = System.Text.UTF8Encoding.UTF8.GetBytes(msg);
int len = msgBs.Length;
byte[] lenBs = BitConverter.GetBytes(len);
byte[] sendBs = new byte[lenBs.Length + msgBs.Length];
lenBs.CopyTo(sendBs, 0);
msgBs.CopyTo(sendBs, lenBs.Length);
try {
netStream.BeginWrite(sendBs, 0, sendBs.Length, new AsyncCallback(SendCallback), netStream);
}
catch (System.Exception e) {
Console.WriteLine(e);
}
}
}
private void SendCallback(IAsyncResult result) {
NetworkStream netStream = (NetworkStream)result.AsyncState;
try {
netStream.EndWrite(result);
netStream.Flush();
netStream.Close();
}
catch (System.Exception e) {
Console.WriteLine(e);
}
}
}
}
}
完成!