C#的Socket网络编程

       这是用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 方法
    /// <summary>
    /// 更新存储字节索引,数量增加
    /// </summary>
    public void AddCount(int count)
    {
        startIndex += count;
    }
    #endregion

    /// <summary>
    /// 读取(解析)客户端发送过来的数据
    /// </summary>
    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();
        }

        /// <summary>
        /// 服务端异步客户端
        /// </summary>
        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 回调事件
        /// <summary>
        /// 服务端异步接收客户端连接
        /// </summary>
        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);
        }

        /// <summary>
        /// 服务端异步获取客户端发送的消息
        /// </summary>
        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地址进行设置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值