这是我的第一篇文章,如果我做错了,请纠正我。
我正在尝试创建一个多线程客户端/服务器应用程序。我没有问题在没有线程的情况下制作一个基本的1对1客户端/服务器应用程序,但我希望每个客户端单独与服务器通信,每个客户端只接收属于控制台中特定客户端的消息。这是我无法工作的地方。
我已经在线查看了一些教程,我试着在Eclipse中调试而没有任何运气。 我希望应用程序做什么:
如果我运行服务器和2个客户端,我希望能够在客户端上编写消息,并使服务器返回消息和消息号而不跳过数字。
客户1:
消息号:0。你说:你好!
消息号:1。你说:什么了!
客户2:
消息号:0。你说:嘿服务器!
消息号:1。你说:你现在在做什么?
它与我运行的第一个客户端一起工作并完美地增加了messagenumber,但是当我创建第二个时它会冻结,所以我想我的问题是使用套接字声明或我的线程方式。 (也许某个地方缺少socket.close()?)
我知道应用程序存在一些其他缺陷,但请记住,这只是一个用于处理线程的学校作业。
如果有人愿意提供帮助,请提前致谢。 :)
服务器代码:
public class Server extends Thread
{
DataInputStream in;
DataOutputStream out;
ServerSocket listener;
public Server() throws IOException
{
try
{
while (true)
{
listener = new ServerSocket(9090);
Socket socket = listener.accept();
System.out.println("Test");
ThreadServer ts = new ThreadServer(socket);
Thread t1 = new Thread(ts);
t1.start();
}
}
finally
{
listener.close();
}
}
public static void main(String[] args) throws IOException
{
new Server();
}
}
客户代码:
public class Client extends JFrame
{
DataOutputStream dos;
BufferedReader input;
String answer = null;
String textString;
Socket s = new Socket("localhost", 9090);
public Client() throws IOException
{
JButton btn = new JButton("run");
final JTextField txf = new JTextField(10);
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try
{
dos = new DataOutputStream(s.getOutputStream());
textString = txf.getText();
dos.writeUTF(textString);
dos.flush();
input = new BufferedReader(new InputStreamReader(s.getInputStream()));
answer = input.readLine();
}
catch (Exception e1)
{
e1.printStackTrace();
}
System.out.println(answer);
}
});
setLayout(new GridLayout(2,2));
add(btn);
add(txf);
setVisible(true);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) throws IOException
{
new Client();
}
}
ThreadServer代码:
public class ThreadServer implements Runnable
{
DataInputStream in;
DataOutputStream out;
public ThreadServer (Socket socket) throws IOException
{
int i = 0;
try
{
while (true)
{
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
try
{
String message = in.readUTF();
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("Message no: " + i + ". You said: " + message);
out.println("Message no: " + i);
}
catch(Exception e)
{
e.printStackTrace();
}
i++;
}
}
finally
{
socket.close();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
}
}
答案 0 :(得分:3)
让我试着解决它。
只创建一个ServerSocket
。从while
循环移到第一行以下。把它放在while
循环之前。
listener = new ServerSocket(9090);
将ThreadServer
的构造函数的代码移至run()
方法,因为它实现了Runnable
但不像Runnable
那样行事类。
public ThreadServer(Socket socket) throws IOException {
this.socket=socket;
}
@Override
public void run() {
...
//code from constructor
}
在Server类中,您正在向客户端写两行,但客户端只读一行。删除额外的行,如下所示
out.println("Message no: " + i + ". You said: " + message);
//out.println("Message no: " + i);
最后一个建议:
在致电readUTF()
之前,请务必检查输入,如下所示:
if (in.available() > 0) {
try {
String message = in.readUTF();
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("Message no: " + i + ". You said: " + message);
//out.println("Message no: " + i);
} catch (Exception e) {
e.printStackTrace();
}
i++;
}
答案 1 :(得分:0)
您的ThreadServer
在构造函数中无限循环,而不是run
方法。
这真是太糟了。 run方法是你应该放置代码的地方。
您还应该遵循评论中的建议并移动套接字创建。
-edit -
对于ThreadServer
也是如此,不要在循环中执行套接字init。只是阅读。
稍后您可能还会发现客户端需要额外的线程。就像现在一样 似乎每个客户端只能在单击动作执行按钮时接收消息, 这可能不是你想要的。这将暴露一些同步问题 你将不得不处理,但大多数你gui库可能实际上帮助你那里。 我处理挥杆已经很久了。
- 再次编辑 - 另外,阅读异常处理。你应该决定你想要的地方 捕获IO异常,而不是随机嵌套try / catch和声明方法 抛弃它们。