我有一个Android设备和一个服务器。服务器可以发送消息告知设备与wifi断开连接。为了快速了解它是如何做到的,这里是一个psudo序列图:
现在有趣的是,当客户端重新连接,并且服务器发送消息时,有时该消息缺少第一个字符,有时它是下一个消息。尽管如此,它在客户端重新连接后很快就会发生。
此处显示了示例循环,从服务器端看到:
while (true) {
server_.transmitMessage("SLAVE", "WIFI");
Thread.sleep(40000);
System.out.println("Should be back");
server_.transmitMessage("SLAVE", "Hi wififims");
Thread.sleep(5000);
}
Android设备的输出:
03-05 15:36:01.200 17152-17180/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650
03-05 15:36:11.080 17152-17181/com.example.bla.psedowifidims I/System.out: Received: WIFI
03-05 15:36:11.080 17152-17181/com.example.bla.psedowifidims I/System.out: Client expecting disconnect.
03-05 15:36:11.080 17152-17181/com.example.bla.psedowifidims I/System.out: Expecting disconnect.
03-05 15:36:11.590 17152-17181/com.example.bla.psedowifidims I/System.out: Killing wifi
03-05 15:36:16.660 17152-17181/com.example.bla.psedowifidims I/System.out: Enableing wifi
03-05 15:36:31.760 17152-17181/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650
03-05 15:36:51.550 17152-17181/com.example.bla.psedowifidims I/System.out: Received: Hi wififims
03-05 15:36:56.780 17152-17181/com.example.bla.psedowifidims I/System.out: Received: IFI
如最后一行所示,重新连接后发送的第二条消息在接收时有缺陷。它应该是“WIFI”。如果我让程序运行一段时间,让我们说5分钟,突然丢失的字符会带来另一条消息:
03-05 15:52:32.480 17152-17181/com.example.bla.psedowifidims I/System.out: Received: WWWWWWWWWWWWIFI
服务器
这是显示的监听服务器:
public void startListening(int port) {
this.port = port;
canceled_ = false;
new Thread(() -> {
try {
System.out.println("Listening for incomming connections on port " + port);
serverSocket_ = new ServerSocket(port);
while (!canceled_) {
ServerClient serverClient = new ServerClient(serverSocket_.accept(), networkReceiver, server_);
serverClient.listen();
serverClient.setIdWithoutTransmission(Long.toString(clientId++));
this.ServerClientList_.add(serverClient);
networkReceiver.onNewClient(serverClient.getId());
System.out.println("Client connected from:" + serverClient.getClientSocket().getInetAddress() +
serverClient.getClientSocket().getPort());
}
} catch (IOException e) {
handleDisconnect();
}
}).start();
}
这个集合是侦听状态的本地ServerClient:
public void listen() {
this.canceled_ = false;
new Thread(() -> {
while (!canceled_) {
try {
if (clientSocket_ == null) {
System.out.println("Socket is null, returning from listening");
return;
}
clientSocket_.setSoTimeout(0);
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket_
.getInputStream()));
String msg = inFromClient.readLine();
if (msg == null) {
super.handleDisconnect();
return;
}
if (handleMessage(msg))
continue;
networkReceiver.onNewMessage(msg);
} catch (IOException e) {
super.handleDisconnect();
}
}
}).start();
}
当服务器传输到客户端时:
public void transmitMessage(String id, String msg) {
for (ServerClient ServerClient : ServerClientList_) {
System.out.println("Does " + id + " equals "+ ServerClient.getId());
if (ServerClient.getId().equals(id)) {
ServerClient.transmitMessage(msg);
return;
}
}
System.out.println("Couldn't find ServerClient.");
}
和serverclient上的实际方法:
public void transmitMessage(String message) {
if (clientSocket_ == null || !clientSocket_.isBound()) {
System.out.println("Not connected, can't transmit. Make sure you are connected to the host\nClientsocket " +
"is null or not bound");
return;
}
DataOutputStream outToServer = null;
try {
outToServer = new DataOutputStream(clientSocket_.getOutputStream());
outToServer.writeBytes(message + '\n');
} catch (IOException e) {
System.out.println("Error while writing to socket - message not delivered");
}
}
处理服务器上的断开连接(客户端发送已处理的消息)。
private boolean handleMessage(final String msg) {
if (msg.equals(EXPECT_DISCONNECT_MSG)) {
EXPECT_DISCONNECT_FLAG(true);
return true;
}
然后当ServerClients侦听器捕获异常时,它会看到引发的标志,并调用:
protected void handleExpectedDisconnect() {
server_.lossOfClient(this);
this.canceled_ = true;
finalizeSockets();
}
lossOfClient只是:
public void lossOfClient(final ServerClient serverClient) {
this.ServerClientList_.remove(serverClient);
System.out.println("Removed client with ID " + serverClient.getId());
System.out.println("Size: " + server_.getServerClientList().size());
}
客户端
使用
初始化客户端 public void connectAndListen(String host, int port) {
this.canceled_ = false;
try {
System.out.println("Conecting to " + host + ":" + port);
clientSocket_ = new Socket(host, port);
clientSocket_.setSoTimeout(2000);
listen();
} catch (IOException e) {
System.out.println("Socket error - restarting");
}
}
public void listen() {
this.canceled_ = false;
new Thread(() -> {
while (!canceled_) {
try {
if (clientSocket_ == null) {
System.out.println("Socket is null, returning from listening");
return;
}
clientSocket_.setSoTimeout(0);
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket_
.getInputStream()));
String msg = inFromClient.readLine();
if (msg == null) {
super.handleDisconnect();
return;
}
if (handleMessage(msg))
continue;
networkReceiver.onNewMessage(msg);
} catch (IOException e) {
super.handleDisconnect();
}
}
}).start();
}
断开连接:
public void disconnect() {
try {
if (clientSocket_ != null && clientSocket_.isBound()) {
System.out.println("Client expecting disconnect.");
EXPECT_DISCONNECT_FLAG(true);
transmitMessage(EXPECT_DISCONNECT_MSG);
Thread.sleep(500);
}
finalizeSockets();
} catch (InterruptedException e) {
System.out.println("Coudln't inform receiver about expected disconnect.");
}
}
public void finalizeSockets() {
if (clientSocket_ != null && clientSocket_.isBound()) {
try {
if (!clientSocket_.isClosed())
clientSocket_.close();
} catch (IOException e) {
System.out.println("Couldn't close clientsocket");
}
clientSocket_ = null;
}
}
有谁能告诉我,我做错了什么?为什么断开/重新连接后收到的消息 - 双方的新套接字都无法传输整个消息?
编辑:
尝试刷新输出流,以确保发送所有字节,但这没有帮助。 最好的问候。
编辑II
尝试:
DataOutputStream outToServer = null;
BufferedReader inFromClient = null;
并且仅在它们为空时创建它们。当套接字关闭时,这些设置为null。同样的问题:
03-05 18:05:00.000 11383-11427/com.example.bla.psedowifidims I/System.out:
Conecting to 192.168.1.77:6650
03-05 18:05:06.470 11383-11428/com.example.bla.psedowifidims I/System.out: Received: Hi wififims
03-05 18:05:11.490 11383-11428/com.example.bla.psedowifidims I/System.out: Received: WIFI
03-05 18:05:11.490 11383-11428/com.example.bla.psedowifidims I/System.out: Client expecting disconnect.
03-05 18:05:11.490 11383-11428/com.example.bla.psedowifidims I/System.out: Expecting disconnect.
03-05 18:05:12.000 11383-11428/com.example.bla.psedowifidims I/System.out: Killing wifi
03-05 18:05:17.090 11383-11428/com.example.bla.psedowifidims I/System.out: Enableing wifi
03-05 18:05:32.180 11383-11428/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650
03-05 18:05:51.530 11383-13368/com.example.bla.psedowifidims I/System.out: Received: i wififims
03-05 18:05:56.560 11383-13368/com.example.bla.psedowifidims I/System.out: Received: IFI
03-05 18:06:38.300 11383-11428/com.example.bla.psedowifidims I/System.out: Received: HWHi wififims
03-05 18:06:43.340 11383-13368/com.example.bla.psedowifidims I/System.out: Received: WIFI
编辑III 通过wireshark跟踪,我可以看到有时像“WIFI”这样的消息被分成两个包,一个是W,另一个是IFI。这似乎是原因,所以我尝试了:
public void listen(){
....
byte[] arbytes = new byte[inFromServer.readInt()];
int length = arbytes.length;
inFromServer.read(arbytes,0,length);
....
}
并在传输
public void transmitMessage(String message) {
....
try {
if(outToServer == null)
outToServer = new DataOutputStream(clientSocket_.getOutputStream());
byte[] databyes = message.getBytes(Charset.forName("UTF-8"));
outToServer.writeInt(databyes.length);
outToServer.write(databyes);
} catch (IOException e) {
System.out.println("Error while writing to socket - message not delivered");
}
}
虽然仍然没有运气:
03-05 20:01:10.810 27328-27353/com.example.bla.psedowifidims I/System.out:
Conecting to 192.168.1.77:6650
03-05 20:01:21.600 27328-27354/com.example.bla.psedowifidims I/System.out: Received: WIFI
03-05 20:01:21.600 27328-27354/com.example.bla.psedowifidims I/System.out: Client expecting disconnect.
03-05 20:01:21.600 27328-27354/com.example.bla.psedowifidims I/System.out: Expecting disconnect.
03-05 20:01:22.110 27328-27354/com.example.bla.psedowifidims I/System.out: Killing wifi
03-05 20:01:27.200 27328-27354/com.example.bla.psedowifidims I/System.out: Enableing wifi
03-05 20:01:42.270 27328-27354/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650
03-05 20:01:42.290 27328-27354/com.example.bla.psedowifidims I/System.out: Percent bad: 0.0
03-05 20:02:01.560 27328-28467/com.example.bla.psedowifidims I/System.out: Received: ififims�������
答案 0 :(得分:0)
好吧 - 我经历了很多考验。我尝试手动发送要传输的数字og字节,然后是数据,然后在客户端进行相应的操作。
虽然这很有效,但是当TCP-Retransmission发生时,不知怎的,它在重新传输的包上得到了错误的大小。对于WriteUTF来说,这是相同的,等等。
不知何故 - 经过多次尝试,我改变了发射器以使用PrintWriter。
public void transmitMessage(String message) {
if (clientSocket_ == null || !clientSocket_.isBound()) {
System.out.println("Not connected, can't transmit. Make sure you are connected to the host\nClientsocket " +
"is null or not bound");
return;
}
try {
if (outToServer == null)
outToServer = new DataOutputStream(clientSocket_.getOutputStream());
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket_.getOutputStream())), true);
pw.println(message);
pw.flush();
} catch (IOException e) {
System.out.println("Error while writing to socket - message not delivered");
}
}
现在一切正常 - 也在重传期间。 如果有人能告诉我为什么这是有效的,我真的很感激!