zoukankan      html  css  js  c++  java
  • 已知服务端数据包格式,客户端怎样用Java实现向服务器端(C#写的)接收和发送数据包(其他同理)

    学习总结,转自http://bbs.csdn.net/topics/380199399

    基于 TCP/IP协议

    问:

    请问客户端怎样用Java实现向服务器端(C#写的)接收和发送数据包(及客户端数据包怎么做),服务器端数据包如下:

    复制代码
    struct PacketHeader
    {
    /// 标志位
    short    PacketFlag;
    
    //Packet Length
    /// 消息包长度(消息包头)
    short    Length;
    //Packet ID
    union{
    /// 消息ID
    int     PacketID;//为了方便和别的程序通讯,消息id还是采用枚举定义,在编译期确定
    /// 类型(0~9系统预留)
    int     MsgType;
    };
    //CheckSum
    /// 序列号
    int     SerialNumber;
    //Client or DispatcherID (special use)
    union{
    /// DispatcherID (special use)
    int     DispatcherID;
    struct {
    short FrontEndID;
    short ClientID;//On FrontEnd
    };
    };
    
    PacketHeader()
    :PacketFlag(PacketFlag_Normal)
    ,Length(sizeof(PacketHeader))
    ,PacketID(0)
    ,SerialNumber(0)
    ,DispatcherID(0)
    {
    
    }
    public:
    /// 消息包头的长度
    static const int MsgHeaderLength = 16;//16
    /// 处理 Msg 所需的最小长度
    static const int MsgMustInfoLength = 4;//(ushort + ushort)
    /// 最大Msg长度(包括消息包头)
    static const int Max_Msg_Size = 32000;//<32K
    /// 最小压缩长度
    static const int Min_Compress_Size = 100;
    /// 分割消息包的大小
    static const int SubPacketLength = 1024;//分割消息包的大小
    
    
    /// 添加标志位
    void   AddFlag(enumMsgFlag flag) {PacketFlag |= flag;}
    /// 获得消息类型
    int    GetType(){return this->PacketID; }
    /// 获得消息包长度
    ushort GetLength(){return this->Length; }
    };
    
    
    /// 二进制消息包
    struct NGA_CoreLib_Export Msg : public PacketHeader
    {
    /// 将Msg转换为Packet
    /**
    使用 TypedTLSMemory 保证线程安全
    */
    static Packet* ToPacket(Msg*);//线程安全
    /// 将Msg转换为Packet
    /**
    使用 TypedTLSMemory 保证线程安全
    */
    Packet* ToPacket();//线程安全
    
    
    
    };
    
    struct SSLMSGSendPublicKey:public Msg
    {
    SSLMSGSendPublicKey()
    {
    this->PacketID = MSG_SSLSendPublicKey;
    this->Length = sizeof(*this);
    int keylen = sizeof(KeyData);
    EncryptFlag = PacketFlag_Compress_Need_Checksum;
    for(int i=0;i<keylen;i++){
    BYTE temp = BYTE(rand()%256);
    KeyData[i] = temp;
    
    }
    }
    uint32 EncryptFlag;
    BYTE  KeyData[128];
    };
    
    msg = buf[]
    
    
    msg =   msg.id 
    复制代码

    回复:

    TCP 的异构系统通信,只能通过字节流进行传递。
    服务器端(C#写的)的数据结构是不能被JAVA客户端识别的。
    在服务器端C#将数据结构转换成字符串,然后JAVA端通过输入流获取socket的字节码。
    如:
                    Socket socket=new Socket("127.0.0.1",4700);
            //向本机的4700端口发出客户请求
            BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
            //由系统标准输入设备构造BufferedReader对象
            PrintWriter os=new PrintWriter(socket.getOutputStream());
            //由Socket对象得到输出流,并构造PrintWriter对象
            BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //由Socket对象得到输入流,并构造相应的BufferedReader对象
            String readline;
            readline=sin.readLine(); //从系统标准输入读入一字符串
            while(!readline.equals("bye")){
            //若从标准输入读入的字符串为 "bye"则停止循环
              os.println(readline);
              //将从系统标准输入读入的字符串输出到Server
              os.flush();
              //刷新输出流,使Server马上收到该字符串
              System.out.println("Client:"+readline);
              //在系统标准输出上打印读入的字符串
              System.out.println("Server:"+is.readLine());
              //从Server读入一字符串,并打印到标准输出上
              readline=sin.readLine(); //从系统标准输入读入一字符串
            } //继续循环
            os.close(); //关闭Socket输出流
            is.close(); //关闭Socket输入流
            socket.close(); //关闭Socket


    JAVA只能获取服务器C#端返回的字节流,然后通过字符串转换成JAVA对象。
    对象数据格式转换字符串的方法,可以参照Json格式。也可以在服务器C#端将数据格式转换成XML格式的字符串。JAVA客户端调用后将XML格式的字符串解析成JAVA对象。

    问:

    首先谢谢你的回答,我也想到用数据流来操作了,但是服务器端现在写好的好像没有数据流相关操作,让我用数据包的方式跟服务器通信。服务器数据包代码如下:

    复制代码
        /// <summary>
        /// 消息包
        /// 内存布局
        /// {
        ///     short  PacketFlag;//特殊的值
        ///     short  PacketLength;//消息包的大小,消息不能大于32k
        ///     int    PacketID;//消息包类型id;从这以后的数据可以加密
        ///     int    SerialNumber;//消息包序列号,网络连接每发一个消息包,这个值+1
        ///     int    DispatcherID;//发送者的id
        ///                         //所以消息头的大小是2+2+4+4+4 = 16
        /// }
        /// </summary>
        public class Packet
        {
            public const short MaxLength = 32000;//32k
            public const short InvalidLength = -1;
            public const short NeedCompressMinLength = 100;
            public const short NoCryptHeaderLength = 4; // 2+2
    
            //消息包标志
            public PacketFlag PacketFlag = PacketFlag.Normal;
    
            public  int PacketID;
    
            /// <summary>
            /// 消息序列号
            /// </summary>
            public int  SerialNumber;
            public int  DispatcherID;//if id <0 ,is -serverid
    protected   PacketWriter m_writer;
    
            public Packet(int packetID)
    :this(packetID,0)
            {
                
            }
    
    public Packet(int packetID,int dispatcherid)
    {
    PacketID = packetID;
    DispatcherID = dispatcherid;
                m_writer = new PacketWriter();/*PacketWriter.CreateInstance()*/;
    }
    
    
            private byte[] m_databuffer; //已经有的数据的缓冲
            private int m_datalength; //已经有的数据的大小
            /// <summary>
            /// 消息总长度
            /// </summary>
            public int Length
            {
                get{
                    if (m_databuffer == null)
                        return Packet.HeaderSize + m_writer.Length;
                    else
                        return m_datalength + m_writer.Length;
                }
                set{
                    if (m_databuffer == null)
                        return;
                    m_datalength = value;
                }
            }
    
            internal byte[] DataBuffer{
                get{
                    return m_databuffer;
                }
                set{
                    m_databuffer = value;
                    if (m_databuffer != null)
                        m_datalength = m_databuffer.Length;
                }
            }
    
    public PacketWriter Writer{
    get{
    return m_writer;
    }
    }
    
            internal virtual byte[] ToArray()
            {
                short packet_length = (short)this.Length;
                bool needcreatebuffer = false;
                if (DataBuffer == null || m_writer.Length > 0)
                    needcreatebuffer = true;
                if (needcreatebuffer)
                {
                    byte[] newbuffer = new byte[packet_length];
                    if (m_databuffer != null)
                    {
                        Buffer.BlockCopy(m_databuffer, 0, newbuffer, 0, m_datalength);
                    }
                    m_databuffer = newbuffer;
                }
                //写消息头
                //ArrayUtility.SetShort(m_databuffer, (short)PacketFlag, 0);
                //ArrayUtility.SetShort(m_databuffer, packet_length, 2);
                //ArrayUtility.SetInt(m_databuffer, this.PacketID, 4);
                //ArrayUtility.SetInt(m_databuffer, this.SerialNumber, 8);
                //ArrayUtility.SetInt(m_databuffer, this.DispatcherID, 12);
    
                WriteHead();
    
                if (needcreatebuffer && m_writer.Length > 0)
                {
                    System.Buffer.BlockCopy(m_writer.ToArray(), 0, m_databuffer,
                        packet_length - m_writer.Length, m_writer.Length);
                    m_writer.Length = 0;
                }
                m_datalength = packet_length;
    
                return m_databuffer;
            }
    
            protected void WriteHead()
            {
                //写消息头
                ArrayUtility.SetShort(m_databuffer, (short)PacketFlag, 0);
                ArrayUtility.SetShort(m_databuffer, (short)this.Length, 2);
                ArrayUtility.SetInt(m_databuffer, this.PacketID, 4);
                ArrayUtility.SetInt(m_databuffer, this.SerialNumber, 8);
                ArrayUtility.SetInt(m_databuffer, this.DispatcherID, 12);
            }
    
            /// <summary>
            /// 消息头大小 2+2+4+4+4 = 16
            /// </summary>
            public static int HeaderSize
            {
                get
                {
                    return 16;
                }
            }
    
            public void Reset()
            {
                DataBuffer = null;
                Writer.Clear();
            }
    
        }
    复制代码


    请问我用数据包的方式要怎样做呢?

    如果不加包报头直接发数据流过去的话,服务器端解析出来不对。。。

    回复:

    public class Packet这个数据包对象是C#里面定义的,客户端当然无法解析。我的意思是用字符串来表示,如json格式的字符串,如:
    "packet{MaxLength:32000;InvalidLength:-1;NeedCompressMinLength:100;NoCryptHeaderLength:4...}"
    JAVA客户端系统拿到这个字符串后,通过字符串处理,把它转换成JAVA对象。

  • 相关阅读:
    英语apyrite红碧玺apyrite单词
    英语SouthRedAgate南红玛瑙
    英语kutnahorite金田黄kutnahorite单词
    英语chalchite蓝绿松石chalchite单词
    单词demantoite翠榴石demantoite英语
    英语fieldyellowstone田黄石fieldyellowstone单词
    Http通讯Util
    redis分布式锁工具类
    永不重复的id生成器
    二维码生成工具类
  • 原文地址:https://www.cnblogs.com/ning1121/p/3470017.html
Copyright © 2011-2022 走看看