【发布时间】:2014-05-10 13:10:39
【问题描述】:
目前我正在使用 Java 开发这个迷你聊天程序,其中多个用户应该能够登录聊天程序并聊天。现在我的程序所做的是将用户(客户端)登录到服务器,并且他们所说的任何内容都会被服务器回显。我想要做的是能够直接发送与另一个客户聊天的请求。
我的想法是创建一个包含客户端用户名及其套接字的哈希映射。当客户端请求与另一个客户端聊天时,它会在 HashMap 中查找该用户的用户名,如果另一个客户端同意聊天,则它会连接套接字。 我不知道如何实现这一点,而且我的程序只接受用户的一个输入并从服务器返回它,然后它停止我不知道为什么。我一直在努力让它工作一段时间,开始让我头疼。
代码如下:
客户端类:
package source;
import java.io.*;
import java.util.*;
import java.net.*;
public class Client implements Runnable {
private Socket socket;
private DataOutputStream dout;
private DataInputStream din;
// Constructor
public Client() {
// Code
}
public Client(String host, int port) {
try {
socket = new Socket(host, port);
System.out.println("connected to " + socket);
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
new Thread(this).start();
} catch (IOException ie) {
System.out.println(ie);
}
}
private void processMessage(String message) {
try {
dout.writeUTF(message);
} catch (IOException ie) {
System.out.println(ie);
}
}
public void run() {
try {
while (true) {
String message = din.readUTF();
System.out.println(message);
}
} catch (IOException ie) {
System.out.println(ie);
}
}
public static void main(String[] args) throws IOException {
while (true) {
String prompt;
Scanner clientPrompt = new Scanner(System.in);
System.out.println("client> ");
prompt = clientPrompt.next();
if (prompt.equals("Emmanuel"))
System.out.println("God With Us");
else if (prompt.equals("goOnline")) {
// Enter a host name
// Enter a portNumber
// Enter a userName
String h, p, u;
System.out.println("Enter hostname: ");
h = clientPrompt.next();
System.out.println("Enter portNumber: ");
p = clientPrompt.next();
System.out.println("Enter userName: ");
u = clientPrompt.next();
goOnline(h, p, u);
} else if (prompt.equals("Exit")) {
clientPrompt.close();
System.exit(1);
} else {
System.out.println("Invalid Input, Try Again");
}
}
}
public static void goOnline(String host, String port, String userName) {
int portNumber = Integer.parseInt(port);
Client c = new Client(host, portNumber);
c.processMessage("Username: " + userName);
String prompt;
Scanner clientPrompt = new Scanner(System.in);
while (true) {
prompt = clientPrompt.next();
c.processMessage(prompt);
c.run();
if (prompt.equals("Exit")) {
System.out.println("Bye Bye");
clientPrompt.close();
}
}
}
}
服务器类:
package source;
import java.io.*;
import java.net.*;
import java.util.*;
public class Server { // The ServerSocket we'll use for accepting new
// connections
private ServerSocket ss;
private HashMap<String, Socket> userInfo = new HashMap<String, Socket>();
// A mapping from sockets to DataOutputStreams.
private Hashtable<Socket, DataOutputStream> outputStreams = new Hashtable<Socket, DataOutputStream>();
// Constructor and while-accept loop all in one.
public Server(int port) throws IOException {
// All we have to do is listen
listen(port);
}
private void listen(int port) throws IOException {
// ServerSocket
ss = new ServerSocket(port);
System.out.println("Listening on " + ss);
while (true) {
Socket s = ss.accept();
System.out.println("Connection from " + s);
DataOutputStream dout = new DataOutputStream(s.getOutputStream());
DataOutputStream userInfo = new DataOutputStream(s.getOutputStream());
outputStreams.put(s, dout);
outputStreams.put(s, userInfo);
new ServerThread(this, s);
}
}
Enumeration<DataOutputStream> getOutputStreams() {
return outputStreams.elements();
}
void sendToAll(String message) {
for (Enumeration<DataOutputStream> e = getOutputStreams(); e.hasMoreElements();) {
// Output Stream
DataOutputStream dout = (DataOutputStream) e.nextElement();
// Send Message
try {
dout.writeUTF(message);
} catch (IOException ie) {
System.out.println(ie);
}
}
}
// Remove socket,
void removeConnection(Socket s) {
// Synchronize
synchronized (outputStreams) {
// Tell the world
System.out.println("Removing connection to " + s);
// Remove it from hashtable
outputStreams.remove(s);
try {
s.close();
} catch (IOException ie) {
System.out.println("Error closing " + s);
ie.printStackTrace();
}
}
}
void addInfo(String user, Socket s) {
userInfo.put(user, s);
}
// Main
static public void main(String args[]) throws Exception {
// Get port
int port = Integer.parseInt(args[0]);
// Create Server object
new Server(port);
}
}
服务器线程:
package source;
import java.io.*;
import java.util.*;
import java.net.*;
public class ServerThread extends Thread { // The Server that spawned us
private Server server;
private Socket socket;
public ServerThread(Server server, Socket socket) {
this.server = server;
this.socket = socket;
start();
}
public void run() {
try {
DataInputStream din = new DataInputStream(socket.getInputStream());
while (true) {
String message = din.readUTF();
StringTokenizer stt = new StringTokenizer(message, " ");
while (stt.hasMoreTokens()) {
String token = stt.nextToken();
if (token.equals("Username:")) {
String username = stt.nextToken();
server.addInfo(username, socket);
}
}
System.out.println("Sending " + message);
server.sendToAll(message);
if (message.equals("Exit")) {
System.out.println("Bye Bye");
server.removeConnection(socket);
System.exit(1);
}
}
} catch (EOFException ie) {
} catch (IOException ie) {
ie.printStackTrace();
} finally {
server.removeConnection(socket);
}
}
}
【问题讨论】:
-
您能否重新格式化您的代码以不使用任何制表符?现在,由于您的编辑器和 StackOverflow 之间对制表符的不同解释,大括号很不稳定,因此很难弄清楚您的代码在做什么。
-
没关系,我不再使用此代码,但无论如何感谢@WarrenDew
-
请注意标签不是关键字。在标签列表中塞满与您的问题相同的词(客户端、服务器、套接字、对等点)将无助于对其进行分类。请务必阅读选择标签时出现的说明!
-
首先不要直接调用
run()方法来启动线程,而不是使用start()方法。