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保证HashMap线程安全的几种方式

《JAVA保证HashMap线程安全的几种方式》HashMap是线程不安全的,这意味着如果多个线程并发地访问和修改同一个HashMap实例,可能会导致数据不一致和其他线程安全问题,本文主要介绍了JAV... 目录1. 使用 Collections.synchronizedMap2. 使用 Concurren

Java Response返回值的最佳处理方案

《JavaResponse返回值的最佳处理方案》在开发Web应用程序时,我们经常需要通过HTTP请求从服务器获取响应数据,这些数据可以是JSON、XML、甚至是文件,本篇文章将详细解析Java中处理... 目录摘要概述核心问题:关键技术点:源码解析示例 1:使用HttpURLConnection获取Resp

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

Java中Switch Case多个条件处理方法举例

《Java中SwitchCase多个条件处理方法举例》Java中switch语句用于根据变量值执行不同代码块,适用于多个条件的处理,:本文主要介绍Java中SwitchCase多个条件处理的相... 目录前言基本语法处理多个条件示例1:合并相同代码的多个case示例2:通过字符串合并多个case进阶用法使用

Java中的Lambda表达式及其应用小结

《Java中的Lambda表达式及其应用小结》Java中的Lambda表达式是一项极具创新性的特性,它使得Java代码更加简洁和高效,尤其是在集合操作和并行处理方面,:本文主要介绍Java中的La... 目录前言1. 什么是Lambda表达式?2. Lambda表达式的基本语法例子1:最简单的Lambda表

Java中Scanner的用法示例小结

《Java中Scanner的用法示例小结》有时候我们在编写代码的时候可能会使用输入和输出,那Java也有自己的输入和输出,今天我们来探究一下,对JavaScanner用法相关知识感兴趣的朋友一起看看吧... 目录前言一 输出二 输入Scanner的使用多组输入三 综合练习:猜数字游戏猜数字前言有时候我们在

Spring Security+JWT如何实现前后端分离权限控制

《SpringSecurity+JWT如何实现前后端分离权限控制》本篇将手把手教你用SpringSecurity+JWT搭建一套完整的登录认证与权限控制体系,具有很好的参考价值,希望对大家... 目录Spring Security+JWT实现前后端分离权限控制实战一、为什么要用 JWT?二、JWT 基本结构

java解析jwt中的payload的用法

《java解析jwt中的payload的用法》:本文主要介绍java解析jwt中的payload的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java解析jwt中的payload1. 使用 jjwt 库步骤 1:添加依赖步骤 2:解析 JWT2. 使用 N

springboot项目如何开启https服务

《springboot项目如何开启https服务》:本文主要介绍springboot项目如何开启https服务方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录springboot项目开启https服务1. 生成SSL证书密钥库使用keytool生成自签名证书将

Java实现优雅日期处理的方案详解

《Java实现优雅日期处理的方案详解》在我们的日常工作中,需要经常处理各种格式,各种类似的的日期或者时间,下面我们就来看看如何使用java处理这样的日期问题吧,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言一、日期的坑1.1 日期格式化陷阱1.2 时区转换二、优雅方案的进阶之路2.1 线程安全重构2