JAVA Socket传输数据和对象

2024-04-27 10:48

本文主要是介绍JAVA Socket传输数据和对象,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1   引子

               Socket通信中,我们要在客户端和服务端中传输数据,传输的数据有各种类型,int,short,long以及String,甚至是自定义的各种Object,我们如何能够保证在服务端和客户端之间的数据能够使得两端都能理解,这就是所谓的“应用协议”;

 

在通信的“管道”中,流的都是二进制数据,所以,双方如何约定好“解析规则”,则就必须要求通信双方都预先制定好协议;

 

2   序列化和反序列化

Java中,有一个借口Serializable接口,这个接口不需要实现实现任何方法,只是一个标识,Java 序列化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从其它地方把该Byte 流里的数据读出来。重新构造一个相同的对象。这种机制允许你将对象通过网络进行传播,并可以随时把对象持久化到数据库、文件等系统里。

 

 

代码如下:

Person

import java.io.Serializable;

import java.util.Date;

 

public class Person implements Serializable {

         private String name;

         private int tall;

         private transient Date birthday;

         private Address address;

 

         public String getName() {

                   return name;

         }

 

         public void setName(String name) {

                   this.name = name;

         }

 

         public int getTall() {

                   return tall;

         }

 

         public void setTall(int tall) {

                   this.tall = tall;

         }

 

         public Date getBirthday() {

                   return birthday;

         }

 

         public void setBirthday(Date birthday) {

                   this.birthday = birthday;

         }

 

         public Address getAddress() {

                   return address;

         }

 

         public void setAddress(Address address) {

                   this.address = address;

         }

 

}

 

Address

package stream.demo;

 

import java.io.Serializable;

 

public class Address implements Serializable{

         private String city;

         private String street;

 

         public Address() {

         }

 

         public Address(String city, String street) {

                   this.city = city;

                   this.street = street;

         }

 

         public String getCity() {

                   return city;

         }

 

         public void setCity(String city) {

                   this.city = city;

         }

 

         public String getStreet() {

                   return street;

         }

 

         public void setStreet(String street) {

                   this.street = street;

         }

 

}

 

我们将这个对象串行化至文件系统,然后将之还原,这个过程其实类似于一个“压扁”和“充气”的过程,请注意,我们的Person类中包含一个嵌入对象,并且birthday变化,将之设置为transient限定符,这表示我们放弃了birthday的串行化;

package stream.demo;

 

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.OutputStream;

import java.util.Date;

 

public class Persistence {

         public static void main(String[] args) {

                   Persistence.savePerson();

                   Persistence.getPerson();

         }

 

         public static void getPerson() {

                   try {

                            InputStream in = new FileInputStream("c://person.dat");

                            ObjectInputStream dataInput = new ObjectInputStream(in);

                            Person p = (Person) dataInput.readObject();

                            System.out.println(p.getName());

                            System.out.println(p.getTall());

                            System.out.println(p.getBirthday());

                            System.out.println(p.getAddress().getCity());

                            System.out.println(p.getAddress().getStreet());

                   } catch (Exception e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                   }

         }

 

         public static void savePerson() {

                   Person p = new Person();

                   p.setName("corey");

                   p.setTall(171);

                   p.setBirthday(new Date());

                   p.setAddress(new Address("yiyang", "ziyang"));

                   OutputStream out = new ByteArrayOutputStream();

                   try {

                            OutputStream fileOut = new FileOutputStream(new File(

                                               "c://person.dat"));

 

                            ObjectOutputStream dataOut = new ObjectOutputStream(fileOut);

                            dataOut.writeObject(p);

 

                            dataOut.close();

                            fileOut.close();

                   } catch (IOException e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                   }

         }

}

 

Console:

corey

171

null

yiyang

ziyang

 

                   可见,我们的目的实现了,并且birthday没有被串行化;如果我们不讲Address实现Serializable,会发生异常:

java.io.WriteAbortedException: writing aborted

 

3   IO

我们都知道JAVAIO是一个极其庞大的类家族,也正是运用了装饰模式的经典场景;

 

可见,我们一部分管道是直接连接了数据源,或者直接输出到数据源,他们能够直接读数据或者写数据,我们上一节中使用的FileoutputStreamFileInputStream就是这样的管道,他们的数据源就是指存在文件系统中的文件;下一部分我们要求使用的ByteArrayInputStreamByteArrayOutputStream也是这样的管道,不过他的数据源是存在内存中的数组;他能够通过write把数据,字符串等等写进这块数组区域,并且能够得到一个完整的字节数组;

而另外的一部分则不能直接与数据源发生读写交互,他主要用于装饰上一部分的管道,给这个管道赋予更加便捷的功能,诸如BufferedReader等等的,主要是提供了缓存,就好比给上一部分管道中间提供了一个“蓄水池”,这个“蓄水池”等到“水流”到了一定的程度的时候,才会一次性的流进或者流出等等,诸如ObjectInputStreamObjectOutputStream,他们能够直接读写一个Object,但是这个Object被写到了哪里,是内存中的字节数组还是文件文件的文件中,而必须委托给其他管道实现;

 

4   在网络中传输对象

在网络中的两台机器中传输对象,前提首先是基于同一个平台,这是序列化的基础,所以这里主要有两种做法:

 

l  采用JAVA的序列化机制,将对象“压扁”成二进制字节,将二进制字节在网络中传输;

l  自定义协议,将对象用字符串描述出来,将字符串用二进制表示,在网络中传输,在另外一边用相反的策略解析这个字符串,重新构造业务对象,这个方法能够在异构平台中进行传输而不变形,但是需要额外的编写“压扁”和“充气”的代码;

 

我们这里用第一种方法:

package stream.demo;

 

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.OutputStream;

import java.util.Date;

 

public class Persistence {

         public static void main(String[] args) {

                   byte[] bs = Persistence.toBytes();

        //在网络中进行传输

                   Persistence.getBytes(bs);

         }

 

         public static byte[] toBytes() {

                   Person p = new Person();

                   p.setName("corey");

                   p.setTall(171);

                   p.setBirthday(new Date());

                   p.setAddress(new Address("yiyang", "ziyang"));

                   ByteArrayOutputStream out = new ByteArrayOutputStream();

                   try {

                            ObjectOutputStream oout = new ObjectOutputStream(out);

                            oout.writeObject(p);

                   } catch (IOException e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                   }

                   return out.toByteArray();

         }

 

         public static void getBytes(byte[] bs) {

                   try {

                            ByteArrayInputStream byteIn = new ByteArrayInputStream(bs);

                            ObjectInputStream in = new ObjectInputStream(byteIn);

                            Person p = (Person) in.readObject();

                            System.out.println(p.getName());

                            System.out.println(p.getTall());

                            System.out.println(p.getBirthday());

                            System.out.println(p.getAddress().getCity());

                            System.out.print(p.getAddress().getStreet());

                   } catch (Exception e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                   }

         }

}

 

其中服务端代码片段为:

in = this.getRequestSocket().getInputStream();

                            out = this.getRequestSocket().getOutputStream();

                            byte[] bs = Persistence.toBytes();

                            System.out.println("发送数字长度:"+bs.length);

                            out.write(bs);

                            this.getRequestSocket().close();

 

客户端代码片段为:

InputStream in = request.getInputStream();

                            byte[] bin = new byte[200];

                            int length = 0;

                            while ((length = in.read(bin)) != -1) {

                                     System.out.println("length:" + length);

                                     Persistence.getBytes(bin);

                            }

 

其中,服务端代码和客服端代码都引用了Person jar包;

这篇关于JAVA Socket传输数据和对象的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/940304

相关文章

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll