客户端与服务器的粘包问题

//客户端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            ScoketClient client = new ScoketClient();

            //测试不停发送消息

            for (int i = 0; i < 10; i++)
            {
                client.SendMessage("Welcom To QiKu Edu,Welcom To QiKu Edu,Welcom To QiKu Edu,Welcom To QiKu Edu,Welcom To QiKu Edu");
            }
            while (true)
            {
                string msg = Console.ReadLine();
                client.SendMessage(msg);
            }
        }
    }
}

public class ScoketClient
{
    /// <summary>
    /// 客户端
    /// </summary>
    /// <param name="args"></param>
    string ip = "192.168.11.36";
    int port = 8500;

    NetworkStream stream;
    byte[] buffer;
    int BuffseSize = 8192;
    public ScoketClient()
    {
        TcpClient clien = new TcpClient();
        clien.Connect(ip, port);

        Console.WriteLine("客户端链接服务器" + clien.Client.RemoteEndPoint);
        stream = clien.GetStream();
        Console.WriteLine("输入需要发送的消息:");

        buffer = new byte[8192];
        stream.BeginRead(buffer, 0, buffer.Length, ReadAsync, null);
    }
    void ReadAsync(IAsyncResult result)
    {
        try
        {
            int readCount = stream.EndRead(result);
            if (readCount == 0) throw new Exception("读取到0字节");

            string msg = Encoding.UTF8.GetString(buffer, 0, readCount);
            Console.WriteLine("接收到消息 ->" + msg);
            //加个锁
            lock (stream)//再次开启读取
            {
                Array.Clear(buffer, 0, buffer.Length);
                stream.BeginRead(buffer, 0, BuffseSize, ReadAsync, null);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    //发送字符信息到服务端的方法
    public void SendMessage(string msg)
    {
        //把内容转为byte[]
        byte[] temp = Encoding.UTF8.GetBytes(msg);//收到消息后转为byte数组
        
        //把长度转为byte[]
        int lenth = temp.Length;//获取收到的消息的长度
        byte[] head = BitConverter.GetBytes(lenth);//将int长度转换为4个byte
        
        //拼接最后的byte数组
        MemoryStream mem = new MemoryStream(); //MemoryStream创建其支持存储区为内存的流。
        mem.Write(head, 0, head.Length);
        mem.Write(temp, 0, temp.Length);

        //发送最终内容
        byte[] result = mem.ToArray();//转为字节流
        stream.Write(result, 0, result.Length);
        Console.WriteLine("发送消息 ->" + msg);
    }
}

//服务器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

class Program
{
    static Dictionary<string, RemoteClient> dic = new Dictionary<string, RemoteClient>();
    static void Main(string[] args)
    {
        IPAddress adress = IPAddress.Parse("192.168.11.36");
        int port = 8500;

        TcpListener linstener = new TcpListener(adress, port);

        linstener.Start();
        Console.WriteLine("开始侦听客户端");

        while (true)
        {
            TcpClient client = linstener.AcceptTcpClient();
            //接收到客户端后,交给RemoteClient去处理
            RemoteClient remote = new RemoteClient(client);
            //存储接收的客户端
            dic.Add(client.Client.RemoteEndPoint.ToString(), remote);
        }
    }

    public static void Broad(TcpClient client, string msg)
    {
        foreach (KeyValuePair<string, RemoteClient> item in dic)
        {
            string message = client.Client.RemoteEndPoint.ToString() + ":发送了:" + msg;
            item.Value.SendMessage(message);
        }
    }
}

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

class RemoteClient
{

    定义一个集合,存储客户端信息
    //static Dictionary<string, Socket> ClientConnectionItems = new Dictionary<string, Socket>() { };
    public const int BufferSize = 8192;
    TcpClient tcpClient;
    NetworkStream stream;//网络流
    byte[] buffer;

    //static List<NetworkStream> streams = new List<NetworkStream>();
    public RemoteClient(TcpClient client)
    {

        创建一个监听线程
        //Thread theadwatch = new Thread(WatchConnecting);
        将窗体线程设置为与后台同步,随着主线程结束而结束
        //theadwatch.IsBackground = true;
        启动线程
        //theadwatch.Start();

        this.tcpClient = client;
        Console.WriteLine(client.Client.RemoteEndPoint + "-> 连接成功");

        stream = client.GetStream();
        //streams.Add(stream);
        buffer = new byte[BufferSize];

        //开启异步读取信息
        stream.BeginRead(buffer, 0, BufferSize, ReadAsync, null);
    }

    void ReadAsync(IAsyncResult result)
    {
        try
        {
            int readCount = stream.EndRead(result);
            if (readCount == 0) throw new Exception("读取到0字节");
            //抛出到逻辑层
            OnReceive(buffer, readCount);

            //加个锁
            lock (stream)//再次开启读取
            {
                Array.Clear(buffer, 0, buffer.Length);
                stream.BeginRead(buffer, 0, BufferSize, ReadAsync, null);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    MemoryStream mem = new MemoryStream();
    //解密消息体
    void OnReceive(byte[] bytes, int count)//源源不断的接收
    {
        mem.Seek(0, SeekOrigin.End);//指针指到结尾
        mem.Write(bytes, 0, count);//读多少写多少
        mem.Seek(0, SeekOrigin.Begin);//指针指向开头

        int headCount = 4;
        while (RemainingBytes() > headCount)//接收多条消息
        {
            byte[] head = new byte[headCount];
            mem.Read(head, 0, headCount);
            int length = BitConverter.ToInt32(head, 0);

            if (RemainingBytes() >= length)//说明后面的内容足够可以截
            {
                //总是没读过的信息
                byte[] content = new byte[length];//字节数组
                mem.Read(content, 0, length);//读他的零位到length位

                string msg = Encoding.UTF8.GetString(content);//指定字节数组解码为字符串
                Console.WriteLine(msg);
            }
            else//如果不够长度
            {
                mem.Position = mem.Position - headCount;
                break;
            }
        }

        //把剩余的写到mem的开头
        byte[] remain = new byte[mem.Length - mem.Position];
        mem.Read(remain, 0, remain.Length);
        mem.SetLength(0);
        mem.Write(remain, 0, remain.Length);
    }

    long RemainingBytes()
    {
        return mem.Length - mem.Position;
    }


    //发送给客户端消息
    public void SendMessage(string msg)
    {
        byte[] temp = Encoding.UTF8.GetBytes(msg);
        //foreach (NetworkStream item in streams)
        //{
        stream.Write(temp, 0, temp.Length);
        //}
        Console.WriteLine("回复客户端 ->" + msg);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值