如何解决如何在 Java 中使用 TCP 协议通过套接字发送序列化类?
澄清一下,这个类保存重要的客户端信息,这些信息必须完整地到达,而不会丢失或损坏信息。 我需要将这个类作为一个变量发送,该变量包含从客户端到服务器的一些客户端信息,服务器将该变量存储在一个数组中。
我可以使用 ObjectOutputStream 发送它,但是使用它发送客户端信息是否安全?如果客户信息到达,我的项目就会成败。 (我只能在我的项目中使用java)
我尝试在互联网上搜索相关的解决方案,但都不够。
我在如何用英语解释 Java 语言方面的知识有限,因为我没有用英语学习这种语言,所以我希望你能理解我的问题。
编辑:添加了类。
public class ClientInformation implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -8904366211043587433L;
private int arrplace;
private int mode;
private int ip;
private String myusername;
private String username;
private int password;
private Dimension screenResolution;
public ClientInformation (int ip,String myusername,String username,int password,Dimension screenResolution,int mode,int arrplace) {
this.ip = ip;
this.myusername = myusername;
this.username = username;
this.password = password;
this.screenResolution = screenResolution;
this.mode = mode;
}
public int getarrplace()
{
return arrplace;
}
public int getmode()
{
return mode;
}
public int getip()
{
return ip;
}
public String getmyusername()
{
return myusername;
}
public String getusername()
{
return username;
}
public int getpass()
{
return password;
}
public Dimension getscreenRes()
{
return screenResolution;
}
public void setarrplace(int arrplace)
{
this.arrplace = arrplace;
}
public void setmode (int mode)
{
this.mode = mode;
}
public void setmyusername (String myusername)
{
this.myusername = myusername;
}
public void setusername (String username)
{
this.username = username;
}
public void setpass(int password)
{
this.password = password;
}
public void setscreenRes(Dimension screenResolution)
{
this.screenResolution = screenResolution;
}
}
解决方法
即使强烈不鼓励使用敏感数据类的序列化/反序列化,您仍然可以实现它,但至少建议严格遵循与此相关的Oracle Java 安全指南话题:
8 Serialization and Deserialization
但是,我也建议您使用 SSL Socket,而不是简单的 Java Socket,这样可以保证通信通道的安全性,从而保证您将通过 {{1 }},并将防止恶意用户的任何篡改尝试。
您可以在此 link 的 Java 证书代码标准页面上找到一些有用的 SSLSocket 使用示例。查看“合规解决方案”并尝试其中的示例。
给你。我为你做了一个完整的实现,它直接在流上写入数据。我建议使用 SSL 套接字或加密流(CipherInput- 和 CipherOutputStream)。 要将此类写入流,只需对其调用 writeTo 并传入 Outputstream 或将 InputStream 读入并传递给其构造函数。
注意:不要忘记在调用相应方法后关闭(和刷新)流。我没有在 writeTo 方法和构造函数中关闭它们,因为您可能仍然需要流来读取或写入更多数据。
给你(我测试过。它功能齐全,甚至可以正确写入和读取空值):
public static final class ClientInformation implements Serializable {
private static final long serialVersionUID = -8904366211043587433L;
private static final Charset CHARSET = StandardCharsets.UTF_8;
private int arrplace;
private int mode;
private int ip;
private String myusername;
private String username;
private final int password;
private Dimension screenResolution;
public ClientInformation(int ip,String myusername,String username,int password,Dimension screenResolution,int mode,int arrplace) {
this.ip = ip;
this.myusername = myusername;
this.username = username;
this.password = password;
this.screenResolution = screenResolution;
this.mode = mode;
this.arrplace = arrplace;
}
public ClientInformation(InputStream in) throws IOException {
int l;
byte[] sb = null,ib = new byte[4];
// Read arrplace
readFully(in,ib,4);
arrplace = getInt(ib,0);
// Read mode
readFully(in,4);
mode = getInt(ib,0);
// Read ip
readFully(in,4);
ip = getInt(ib,0);
// Read myusername
readFully(in,4);
l = getInt(ib,0);
sb = resize(sb,l);
if (l >= 0) {
readFully(in,sb,l);
myusername = new String(sb,l,CHARSET);
} else {
myusername = null;
}
// Read username
readFully(in,l);
username = new String(sb,CHARSET);
} else {
username = null;
}
// Read password
readFully(in,4);
password = getInt(ib,0);
// Read screenWidth
readFully(in,4);
int screenWidth = getInt(ib,0);
// Read screenHeight
readFully(in,4);
int screenHeight = getInt(ib,0);
screenResolution = new Dimension(
screenWidth,screenHeight
);
}
public void writeTo(OutputStream os) throws IOException {
String s;
int l;
byte[] sb,ib = new byte[4];
// Write arrplace
putInt(ib,arrplace);
os.write(ib,4);
// Write mode
putInt(ib,mode);
os.write(ib,4);
// Write ip
putInt(ib,ip);
os.write(ib,4);
// Write myusername
s = myusername;
if (s != null) {
sb = s.getBytes(CHARSET);
putInt(ib,l = sb.length);
os.write(ib,4);
os.write(sb,l);
} else {
putInt(ib,-1);
os.write(ib,4);
}
// Write username
s = username;
if (s != null) {
sb = s.getBytes(CHARSET);
putInt(ib,4);
}
// Write password
putInt(ib,password);
os.write(ib,4);
Dimension screenRes = screenResolution;
// Write screenRes.getWidth()
putInt(ib,(int) screenRes.getWidth()); // Get width actually returns an integer
os.write(ib,4);
// Write screenRes.getHeight()
putInt(ib,(int) screenRes.getHeight()); // Get height actually returns an integer
os.write(ib,4);
}
static byte[] resize(byte[] b,int newLen) {
if (newLen < 0) return b;
if (b == null || b.length < newLen) {
return new byte[newLen];
} else return b;
}
static void putInt(byte[] b,int off,int val) {
b[off + 3] = (byte) (val);
b[off + 2] = (byte) (val >>> 8);
b[off + 1] = (byte) (val >>> 16);
b[off] = (byte) (val >>> 24);
}
static int getInt(byte[] b,int off) {
return ((b[off + 3] & 0xFF)) +
((b[off + 2] & 0xFF) << 8) +
((b[off + 1] & 0xFF) << 16) +
((b[off]) << 24);
}
static void readFully(InputStream in,byte[] b,int len) throws IOException {
int n = 0;
while (n < len) {
int count = in.read(b,off + n,len - n);
if (count < 0) {
throw new EOFException();
}
n += count;
}
}
// Don't forget to add all the getters and setter you had
}
这是我用来测试这个类的示例代码:
try {
// Serialize
ClientInformation info = new ClientInformation(
30,"MyUsername","My Real Username",3485,new Dimension(300,200),19,20
);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
info.writeTo(bos);
bos.flush();
// Deserialize
ByteArrayInputStream in = new ByteArrayInputStream(bos.toByteArray());
ClientInformation receivedInfo = new ClientInformation(in);
System.out.println(receivedInfo.ip);
System.out.println(receivedInfo.myusername);
System.out.println(receivedInfo.username);
System.out.println(receivedInfo.password);
System.out.println(receivedInfo.screenResolution);
System.out.println(receivedInfo.mode);
System.out.println(receivedInfo.arrplace);
} catch (Throwable tr) {
tr.printStackTrace();
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。