简体   繁体   English

在Java中的套接字上编写协议时遇到问题

[英]Problems writing a protocol on top of sockets in Java

I'm writing a protocol on top of sockets, so I've decided to implement headers then send the information. 我在套接字顶部编写了一个协议,因此我决定实现标头,然后发送信息。 So there is one thread per connection on the server which sits there reading in headers, then delegates off to methods to read in the rest of the information when it arrives. 因此,服务器上每个连接都有一个线程,该线程坐在那里读取标头,然后委派给方法,以在到达时读取其余信息。

So essentially it looks like this: 因此,基本上看起来像这样:

while ((length = inStream.read(buffer)) != -1)
{
   dispatch(buffer, length);
}

So the dispatch method then decrypts the headers and delegates the method depending what is found in the header. 因此,调度方法然后解密标头,并根据标头中的内容委托该方法。 It looks similar to: 它看起来类似于:

byte[] clearText = decrypt(message,length);
if (cleartext == foo) sendFooToSocket();

So then sendFooToSocket() would then sit there and read from the instream or send to the outstream. 因此,然后sendFooToSocket()将坐在那里,从流内读取或发送到流外。 This is where I seem to run into some problems, in the client I'm sending the header then flushing, then sending the rest of the data, but it appears it's all coming as one and not being split up into header then data. 这似乎是我遇到的一些问题,在客户端中,我先发送标头,然后进行刷新,然后发送其余数据,但看起来它们全都成为一个,而不是拆分为标头和数据。 Also is there a best way to force out of the sendFooToSocket method? 还有没有强制退出sendFooToSocket方法的最佳方法?

public void sendFooToSocket()
{
  byte[] buffer = new byte[1024];
  int length = 0;
  while ((length = inStream.read(buffer) >0)
  {
    message = decrypt(buffer, length);
  }
}

I would assume flush would allow me to break out of this method as it closes then opens the stream? 我想冲洗可以让我打破这种方法,因为它关闭然后打开流?

So I have 2 problems, flush doesn't seem to be breaking up my messages and flush doesn't seem to be allowing to drop out of methods such as sendFooToSocket(), any suggestions? 所以我有2个问题,冲洗似乎并没有破坏我的消息,冲洗似乎也不允许退出sendFooToSocket()之类的方法,有什么建议吗?

For clarity sake, the client just does this: 为了清楚起见,客户端只是这样做:

byte[] header = "MESG".getBytes();
cipher = encrypt(header);
outStream.write(cipher,0,cipher.length);
outStream.flush();
byte[] message = "Hi server".getBytes();
cipher = encrypt(message);
outStream.write(cipher,0,cipher.length);
outStream.flush();

But this is received by the server as 1 message even though it's been flushed after every write. 但是,即使每次写入后都将其刷新,服务器仍会将其作为1条消息接收。 Sending just the header works, and we get stuck in the sendFooToSocket() method, but if I send the data after the flush it comes all at once. 仅发送标头即可,我们陷入sendFooToSocket()方法中,但是如果在刷新后发送数据,则一次全部发送。

The client uses OutputStream and InputStreams just from the socket.get. 客户端仅从socket.get使用OutputStream和InputStreams。 The client also uses OutputStream and InputStream. 客户端还使用OutputStream和InputStream。 Not sure if this matters? 不确定这是否重要?

What you seem to want is "record boundaries". 您似乎想要的是“记录边界”。 With streams in general there are no implicit record boundaries. 通常,对于流,没有隐式记录边界。 If you want that kind of functionality you will need to implement it yourself, by buffering the input and looking for, say, newlines to indicate the end of a record. 如果您想要这种功能,则需要自己进行实现,方法是缓冲输入并查找换行符以指示记录的结尾。

Look at BufferedInputStream. 查看BufferedInputStream。

inStream.read() may not be returning on a message boundary. inStream.read()可能不在消息边界上返回。 You can't assume that it'll return at any particular boundary (such as a blank line separating headers and content if that's how you're doing it.) You'll have to manually parse the content and ignore the fact that it could come from multiple read()s or maybe one read() contains both the headers and content. 您不能假设它会在任何特定的边界处返回(例如,如果这是将标题和内容分开的空白行,则是这样)。您将不得不手动解析内容,而忽略了它可以来自多个read()或一个read()包含标头和内容。

Unless you actually want control at the level you have implemented, you could consider Object streams (see ObjectInputStream and ObjectOutputStream). 除非您实际上想要在实现的级别进行控制,否则可以考虑对象流(请参阅ObjectInputStream和ObjectOutputStream)。 Such streams will allow you to send Java Objects over sockets and read them at the other end with out having to deal with headers and boundaries etc. See ObjectOutputStream for more details, but it's pretty much: 这样的流将允许您通过套接字发送Java对象,并在另一端读取它们,而不必处理标头和边界等。有关更多详细信息,请参见ObjectOutputStream ,但实际上很多:

Sender: writeObject(objectX) 发件人:writeObject(objectX)

Receiver: myCopyOfObjectx = readObject() 接收者:myCopyOfObjectx = readObject()

and you can send any objects you like (as long as they are Serializable). 并且您可以发送任何您喜欢的对象(只要它们是可序列化的)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM