【发布时间】:2017-02-27 21:06:10
【问题描述】:
我正在尝试实现客户端-服务器通信。 我尝试了异步的,现在我正在绑定同步的,但只是为了让它工作。我尽可能多地切断了不必要的代码,即使经过一天的研究,我也无法让它工作。拜托,如果你能救我,我将不胜感激!
我现在将说明问题并指出代码的某些部分,请理解所有代码都在下面提供
问题: 在 main.java 中
我创建一个服务器和客户端,然后发送数据。
s.InitiateRead()
是一个函数,它只会永远循环并尝试从 DataInputStream 中读取一个 int
len = BReaderForClient.readInt();
你也可以看到类似的代码
c.Send(ByteBuffer.wrap("A".getBytes()));
这仅发送数字 12,而不是任何 A 或其他东西,最终(在线程中)调用的方法是这个(位于 ClientServerBase.java 中):
void Send_Begin(ByteBuffer Data, DataOutputStream OutputStream) {
try {
while(CurrentlyWritingToOutputStream)
{ /* wait */ }
CurrentlyWritingToOutputStream = true;
OutputStream.writeInt(12);
OutputStream.flush();
CurrentlyWritingToOutputStream = false;
Send_End(false);
} catch (IOException e) {
Send_End(true);
}
}
如您所见,我有用于从多个线程写入的信号量。
所以我写了 3 次 Integer 到流,然后我在线程中调用读,然后继续写更多。 这个测试的重点是用数据淹没套接字,就好像你在每次发送之间放置 Thread.Sleep(5000) 一样,一切都会好的。
问题是,运行时,有时读取的输出不是预期的 12 号。
请注意,在 main.java 中注释的 while 循环可以取消注释,仍然给出错误的输出(只是说如果主线程结束,它会杀死所有其他线程)
所有代码:
main.java
package net;
import java.nio.ByteBuffer;
public class main {
public static void main(String[] args) throws Exception {
Server s = new Server();
s.Start();
if(!s.Listen())
return;
Client c = new Client();
c.Send(ByteBuffer.wrap("A".getBytes()));
c.Send(ByteBuffer.wrap("A".getBytes()));
c.Send(ByteBuffer.wrap("A".getBytes()));
new Thread(new Runnable() {
public void run() {
s.InitiateRead();
}
}).start();
c.Send(ByteBuffer.wrap("A".getBytes()));
c.Send(ByteBuffer.wrap("A".getBytes()));
c.Send(ByteBuffer.wrap("A".getBytes()));
/*while(true)
{}*/
}
}
服务器.java
package net;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
public class Server extends ClientServerBase {
public Server()
{
super(ClientServerBase.REAL_TYPE.SERVER);
}
// ======================================================================================
void Accept_Begin() {
Socket socket = null;
try {
socket = serverSocket.accept();
} catch (IOException e) {
Accept_End(true, socket);
return;
}
Accept_End(false, socket);
}
public void InitiateRead()
{
while(true){
int len = 0;
try {
len = BReaderForClient.readInt();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Print("Red: " + len);
}
}
void Accept_End(boolean error, Socket acceptedclient) {
try {
if (!error) {
Print("Client accepted");
Clientsock = acceptedclient;
BwriterForClient = new DataOutputStream(acceptedclient.getOutputStream());
BReaderForClient = new DataInputStream(acceptedclient.getInputStream());
}
} catch (IOException e) {
e.printStackTrace();
}
Accept_Begin();
}
public void close() throws IOException {
BwriterForClient.close();
Clientsock.close();
serverSocket.close();
}
public boolean Listen() {
if(serverSocket == null)
{
Print("Can not listen, Start() was not called.");
return false;
}
new Thread(new Runnable() {
public void run() {
Accept_Begin();
}
}).start();
return true;
}
public boolean Start()
{
try
{
serverSocket = new ServerSocket(1254);
}
catch (IOException e)
{
Print("Can not host, port is probably already in use");
return false;
}
return true;
}
public void Send(ByteBuffer b) {
Send_In_Thread(b, BwriterForClient);
}
Socket Clientsock;
ServerSocket serverSocket;
DataOutputStream BwriterForClient;
DataInputStream BReaderForClient;
}
客户端.java
package net;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
public class Client extends ClientServerBase {
public Client() throws UnknownHostException, IOException
{
super(ClientServerBase.REAL_TYPE.CLIENT);
ClientSocket = new Socket("localhost", 1254);
DIS = new DataInputStream(ClientSocket.getInputStream());
DOS = new DataOutputStream(ClientSocket.getOutputStream());
//Read_In_Thread(DIS);
}
public void close() throws IOException {
DIS.close();
DOS.close();
ClientSocket.close();
}
/**
* @brief Sends data to the server. That is done in thread
* @param Data
*/
public void Send(ByteBuffer Data) {
Send_In_Thread(Data, DOS);
}
Socket ClientSocket;
DataInputStream DIS;
DataOutputStream DOS;
}
ClientServerBase.java(通用库)
package net;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
public abstract class ClientServerBase {
protected enum REAL_TYPE
{
CLIENT,
SERVER
}
protected ClientServerBase(final REAL_TYPE r)
{
CurrentlyWritingToOutputStream = false;
ReadThreadRunning = false;
real_type = r;
}
//=============================================================================
protected void Print(String s)
{
if(real_type == REAL_TYPE.CLIENT)
s = "Client: " + s;
else
s = "Server: " + s;
System.out.println(s);
}
void Send_Begin(ByteBuffer Data, DataOutputStream OutputStream) {
try {
while(CurrentlyWritingToOutputStream)
{ /* wait */ }
CurrentlyWritingToOutputStream = true;
OutputStream.writeInt(12);
OutputStream.flush();
CurrentlyWritingToOutputStream = false;
Send_End(false);
} catch (IOException e) {
Send_End(true);
}
}
void Send_End(boolean Error) {
if (!Error)
Print("Data sent sucessfully");
else
Print("There was an error sending data");
}
protected void Send_In_Thread(ByteBuffer Data, DataOutputStream OutputStream) {
new Thread(new Runnable() {
public void run() {
Send_Begin(Data, OutputStream);
}
}).start();
}
boolean ReadThreadRunning;
boolean CurrentlyWritingToOutputStream;
/**
* Real type of object
*/
REAL_TYPE real_type;
}
程序的输出:
Server: Client accepted
Client: Data sent sucessfully
Client: Data sent sucessfully
Client: Data sent sucessfully
Server: Red: 12
Server: Red: 0
Client: Data sent sucessfully
Client: Data sent sucessfully
Server: Red: 3084
Client: Data sent sucessfully
Server: Red: 12
Server: Red: 0
Server: Red: 201326604
如您所见,有时它会读取 0,甚至是一些未初始化的值。 拜托,你能帮帮我吗?我无法解释也无法理解,这到底是怎么可能的。 我对我正在使用的所有函数进行了红色文档,但这仍然是一个谜。
非常感谢您提供任何可能的帮助
【问题讨论】:
-
虽然它本身显然不能解决问题,但在 Java 中使用 camel case 几乎是 generally accepted convention 并且适用于 JDK。我建议坚持下去。
-
这里没有信号量,只有一个布尔变量,这还不够。您应该使用同步、等待/通知或适当的信号量。