`

一个简单的自定义通信协议(socket) .

 
阅读更多

一个简单的自定义通信协议(socket)

转自:http://vtrtbb.javaeye.com/blog/849336

这是转自javaeye的一篇文章,作者是vtrtbb。

按照网络通信的传统,我们都会自定义协议,这有很多好处,大家可以自己体会(嘿嘿)。

 

 

一直不知道socket通信时候自定义数据包是什么样子的,偶然做了个小例子。

 

先来说说数据包的定义,我这里是包头+内容 组成的:其中包头内容分为包类型+包长度, 那就是 消息对象=包类型+包长度+消息体

 

包类型 byte 型

包长度 int 型

消息体 byte[]

 

包总长度为 1 + 4 +  消息体.getBytes().length

 

发包方法如下:

  1. private void sendTextMsg(DataOutputStream out,String msg ) throws IOException {    
  2.         byte[] bytes= msg.getBytes();    
  3.         int totalLen = 1 + 4 + bytes.length;    
  4.                                 out.writeByte(1);    
  5.         out.writeInt(totalLen);    
  6.         out.write(bytes);    
  7.         out.flush();    
  8.     }    

 

 

 

客户端发送消息类为:

  1. import java.io.DataOutputStream;    
  2. import java.io.IOException;    
  3. import java.io.InputStream;    
  4. import java.io.OutputStream;    
  5. import java.net.Socket;    
  6. import java.net.UnknownHostException;    
  7. import java.util.Scanner;    
  8.     
  9. public class MsgClient {    
  10.     
  11.     private DataOutputStream outs;    
  12.         
  13.     public static void main(String[] args) {    
  14.         try {    
  15.             MsgClient client = new MsgClient();    
  16.             client.connServer("127.0.0.1"9292);               
  17.         } catch (UnknownHostException e) {    
  18.             e.printStackTrace();    
  19.         } catch (IOException e) {    
  20.             e.printStackTrace();    
  21.         }    
  22.     }    
  23.         
  24.         
  25.     private void sendTextMsg(DataOutputStream out,String msg ) throws IOException {    
  26.         byte[] bytes= msg.getBytes();    
  27.         int totalLen = 1 + 4 + bytes.length;    
  28.         out.writeByte(1);    
  29.         out.writeInt(totalLen);    
  30.         out.write(bytes);    
  31.         out.flush();    
  32.     }       
  33.         
  34.     public void connServer(String ip,int port) throws UnknownHostException, IOException {    
  35.         Socket client = new Socket(ip,port);    
  36.         InputStream in = client.getInputStream();    
  37.         OutputStream out = client.getOutputStream();    
  38.         outs = new DataOutputStream(out);    
  39.         while(true) {    
  40.             Scanner scaner = new Scanner(System.in);    
  41.             sendTextMsg(outs, "测试消");    
  42.         }           
  43.     }    

 

 

 

服务端接收类为:

  1. import java.io.DataInputStream;    
  2. import java.io.FileOutputStream;    
  3. import java.io.IOException;    
  4. import java.io.InputStream;    
  5. import java.net.ServerSocket;    
  6. import java.net.Socket;    
  7.     
  8. public class MsgServer {    
  9.     public static void main(String[] args) {            
  10.         try {    
  11.             MsgServer server = new MsgServer();    
  12.             server.setUpServer(9090);    
  13.         } catch (IOException e) {    
  14.             e.printStackTrace();    
  15.         }    
  16.     }    
  17.         
  18.     public void setUpServer(int port) throws IOException {    
  19.         ServerSocket server = new ServerSocket(port);    
  20.         while(true) {    
  21.             Socket client = server.accept();    
  22.             System.out.println("客户端IP:"+client.getRemoteSocketAddress());    
  23.             processMesage(client);    
  24.         }    
  25.     }    
  26.         
  27.     private void processMesage(Socket client) throws IOException {    
  28.         InputStream ins = client.getInputStream();          
  29.         DataInputStream dins = new DataInputStream(ins);    
  30.         //服务端解包过程     
  31.         while(true) {    
  32.             int totalLen = dins.readInt();    
  33.             byte flag = dins.readByte();    
  34.             System.out.println("接收消息类型"+flag);    
  35.                 
  36.             byte[] data = new byte[totalLen - 4 - 1];    
  37.             dins.readFully(data);    
  38.             String msg = new String(data);    
  39.             System.out.println("发来的内容是:"+msg);      
  40.         }    
  41.     }    
  42. }    

 

 

 

 

这样就基本完成了,但实际还有好多问题,比如说服务端用如何用多线程服务来完成客户端的请求已提高效率,如果是NIO方式怎么来实现?多个消息类型时候怎么抽象?这些都没有考虑

 

另外有两个开源的框架不错,一个是apache  mina 还有个是netty ,有机会试试。

 

 

另一篇文章中叙述:

------------------

TCP Socket协议定义

------------------

本文从这里开始,主要介绍TCP的socket编程。

新手们(例如当初的我),第一次写socket,总是以为在发送方压入一个"Helloworld",接收方收到了这个字符串,就“精通”了Socket编程了。而实际上,这种编程根本不可能用在现实项目,因为:

 

1. socket在传输过程中,helloworld有可能被拆分了,分段到达客户端),例如 hello   +   world,一个分段就是一个包(Package),这个就是分包问题

 

2. socket在传输过成功,不同时间发送的数据包有可能被合并,同时到达了客户端,这个就是黏包问题。例如发送方发送了hello+world,而接收方可能一次就接受了helloworld.

 

3. socket会自动在每个包后面补n个 0x0 byte,分割包。具体怎么去补,这个我就没有深入了解。

 

4. 不同的数据类型转化为byte的长度是不同的,例如int转为byte是4位(int32),这样我们在制作socket协议的时候要特别小心了。具体可以使用以下代码去测试:

代码
        public void test()
        {
            
int myInt = 1;
            
byte[] bytes = new byte[1024];
            BinaryWriter writer 
= new BinaryWriter(new MemoryStream(bytes));
            writer.Write(myInt);
            writer.Write(
"j");
            writer.Close();
        }

 

 

尽管socket环境如此恶劣,但是TCP的链接也至少保证了:

  • 包发送顺序在传输过程中是不会改变的,例如发送方发送 H E L L,那么接收方一定也是顺序收到H E L L,这个是TCP协议承诺的,因此这点成为我们解决分包、黏包问题的关键。
  • 如果发送方发送的是helloworld, 传输过程中分割成为hello+world,那么TCP保证了在hello与world之间没有其他的byte。但是不能保证helloworld和下一个命令之间没有其他的byte。

 

因此,如果我们要使用socket编程,就一定要编写自己的协议。目前业界主要采取的协议定义方式是:包头+包体长度+包体。具体如下:

 

1. 一般包头使用一个int定义,例如int = 173173173;作用是区分每一个有效的数据包,因此我们的服务器可以通过这个int去切割、合并包,组装出完整的传输协议。有人使用回车字符去分割包体,例如常见的SMTP/POP协议,这种做法在特定的协议是没有问题的,可是如果我们传输的信息内容自带了回车字符串,那么就糟糕了。所以在设计协议的时候要特别小心。

 

2. 包体长度使用一个int定义,这个长度表示包体所占的比特流长度,用于服务器正确读取并分割出包。

 

3. 包体就是自定义的一些协议内容,例如是对像序列化的内容(现有的系统已经很常见了,使用对象序列化、反序列化能够极大简化开发流程,等版本稳定后再转入手工压入byte操作)。

 

一个实际编写的例子:比如我要传输2个整型 int = 1, int = 2,那么实际传输的数据包如下:

   173173173               8                  1         2

|------包头------|----包体长度----|--------包体--------|

这个数据包就是4个整型,总长度 = 4*4  = 16。

 

 

分享到:
评论

相关推荐

    socket.io,socket.io-client下载

    Socket.IO和Socket.IO-Client是两个非常重要的库,主要用于实现实时双向通信,尤其是在Web开发领域。它们使得JavaScript客户端(浏览器)与Node.js服务器之间能够建立WebSocket风格的连接,提供了强大的实时通信解决...

    socket.io.js下载

    Socket.IO 是一个实时应用程序框架,它为Web开发者提供了一种简单、高效的通信方式,支持WebSocket以及其他多种协议。在本文中,我们将深入探讨Socket.IO的核心概念、功能以及如何使用socket.io.js文件。 WebSocket...

    C#解决socket粘包问题,通信提供了一个自定义通信协议类MsgProtol,该类封装了打包和解包方法,可以解决分包和粘包问题

    C#解决socket通信过程中粘包分包问题,本项目是一个只有6个C#代码文件的开源小工程,用来学习基于TCP的套接字通信包,可以自定义通信协议,处理分包和粘包,内置一个服务端和客户端的套接字程序,也有测试代码和对应...

    C实现基于Socket实现自定义协议通信

    在IT行业中,网络通信是至关重要的一个领域,而Socket编程是构建网络应用程序的基础。本教程主要聚焦于如何使用C语言实现基于Socket的自定义协议通信,涵盖了客户端和服务端的实现。我们将深入理解Socket编程的基本...

    java socket通信自定义消息协议

    总的来说,Java Socket通信自定义消息协议涉及网络编程基础、数据结构设计以及异常处理等多方面知识。通过这个过程,我们可以灵活地构建满足特定需求的通信系统,实现客户端和服务器间的高效交互。

    socket.io API文档

    Socket.IO 是一个非常流行的JavaScript库,它能够实现浏览器与服务器之间的实时双向通信。它不仅支持WebSocket协议,还能够通过其他方式(如轮询)作为回退方案,确保在各种环境中都能提供稳定的服务。 #### 二、...

    Socket.IO demo程序

    Socket.IO 是一个实时应用框架,它为开发人员提供了一种简单的方式来实现在Web上进行双向通信,即服务器和客户端之间的实时、低延迟的数据传输。在Java环境中,我们可以使用Socket.IO的Java客户端库来构建这样的应用...

    SuperSocket.ClientEngine.Core socket 客户端处理粘包半包

    - **自定义协议解析器**:SuperSocket提供了一个灵活的模型,允许用户自定义协议解析器。通过实现`IReceiveFilter`接口,可以编写自己的数据解析逻辑,以适应特定的粘包和半包处理需求。 - **使用预定义的...

    socket.io api

    Socket.IO 是一个实时应用框架,它为开发人员提供了一种简单的方式来实现实时、双向通信。这个框架在Web上广泛使用,特别是在构建实时聊天、协作工具、游戏等应用时。Socket.IO API 提供了多种传输机制,以确保数据...

    swift-socket.io-client-swiftSocket.IO客户端

    2. **初始化**:在应用中创建一个Socket.IO实例,指定服务器地址。 3. **连接**:调用`connect()`方法建立连接。 4. **事件监听**:使用`on()`方法注册事件处理器。 5. **发送数据**:使用`emit()`方法发送事件和...

    基于socket简单通信协议实现

    本主题将深入探讨如何实现基于Socket的简单通信协议,主要包括以下几个方面: 一、Socket基本概念 Socket,通常称为套接字,是网络编程中的一个抽象概念,用于在网络上的两个进程间建立通信连接。在TCP/IP协议栈中...

    使用JS+socket.io+WebRTC+nodejs+express搭建一个简易版远程视频聊天

    在本文中,我们将深入探讨如何使用JavaScript、socket.io、WebRTC、Node.js和Express搭建一个简易版的远程视频聊天应用。这些技术都是现代Web开发中的关键组件,它们各自扮演着不同的角色,共同构建出实时、低延迟的...

    socket.io不错的websocket

    而“工具”则表明Socket.IO是一个实用的开发工具,可以简化Web实时通信的复杂性。 至于文件名“LoginQin-NoChat-7487315”,可能是某个项目或示例代码的名称,具体关联到Socket.IO的登录或聊天功能,但没有更多信息...

    express4.X框架中使用socket.io

    Express是一个强大的Node.js web应用程序框架,而Socket.IO则是一个库,它允许在浏览器和服务器之间进行实时通信,通过WebSocket协议并补充其他几种降级方案。 首先,我们需要安装`socket.io`和`express`。在项目根...

    socket.io源码

    Socket.IO 是一个实时应用框架,它为开发人员提供了一种简单的方式来实现实时、双向通信。这个源码包是 C++ 实现的 Socket.IO 客户端库,名为 "socket.io-clientpp",位于 "socket.io-clientpp-master" 压缩包中。...

    SuperSocket.ClientEngine.QuickStart.zip

    本篇文章将深入探讨如何利用SuperSocket和Netty实现Protobuf协议,并提供一个简单的快速入门指南。 首先,让我们了解一下SuperSocket。SuperSocket是一个轻量级的.NET Socket服务器开发框架,它简化了网络编程的...

    C++实现的Socket接口实现自定义协议通信.zip

    运输层协议采用 TCP 客户端采用交互菜单形式,用户可以选择以下功能: a) 连接:请求连接到指定地址和端口的服务端。 b) 断开连接:断开与服务端的连接。 获取时间: 请求服务端给出当前时间。 获取名字:请求服务端...

    socket.io.rar

    Socket.IO 是一个实时应用框架,它为Web开发者提供了一种简单、强大且可靠的在客户端(通常是浏览器)和服务器之间建立实时双向通信的方法。这个“socket.io.rar”文件包含的“socket.io.js”是Socket.IO的...

    SuperSocket.rar

    SuperSocket支持多种协议,包括TCP、UDP等,并允许开发者根据需求快速构建自己的网络通信协议。在标题中提到的"SuperSocket.ClientEngine.dll"是SuperSocket客户端引擎的一部分,它包含了客户端连接和服务交互的核心...

    C#使用SuperSocket实现自定义协议实现CS架构服务器和客户端程序设计).zip

    2. **SuperSocket库**:SuperSocket是一个强大的.NET Socket服务端开发框架,它提供了一种简单的方式来创建自定义的Socket服务。SuperSocket支持多种协议,允许开发者轻松实现TCP/IP通信,而无需深入理解网络编程的...

Global site tag (gtag.js) - Google Analytics