【问题标题】:Running a Client-Server Chat program运行客户端-服务器聊天程序
【发布时间】:2011-06-28 17:05:36
【问题描述】:

这是网络上最常见的应用场景之一。我没有问任何关于我所做的 java 代码的问题,因为我成功地在我的笔记本电脑上运行了它,其中 .java 文件的客户端和服务器部分都驻留。相反,我在让它在两台计算机之间工作时遇到了问题。我尝试使用交叉电缆建立物理连接以连接两台计算机,并进行了测试以查看文件传输是否成功,但是确实将.java文件的一个服务器部分保留在一台计算机中,将客户端部分保留在另一台计算机中,我尝试先运行服务器,然后运行客户端,但出现“拒绝访问”错误。

这里是我的两个 .java 文件供参考:

/* ChatClient.java */
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class ChatClient {
private static int port = 5000; /* port to connect to */
private static String host = "localhost"; /* host to connect to (server's IP)*/
private static BufferedReader stdIn;
private static String nick;
/**
* Read in a nickname from stdin and attempt to authenticate with the
* server by sending a NICK command to @out. If the response from @in
* is not equal to "OK" go bacl and read a nickname again
*/
private static String getNick(BufferedReader in,
PrintWriter out) throws IOException {

System.out.print("Enter your nick: ");
String msg = stdIn.readLine();
out.println("NICK " + msg);
String serverResponse = in.readLine();
if ("SERVER: OK".equals(serverResponse)) return msg;
System.out.println(serverResponse);
return getNick(in, out);
}
public static void main (String[] args) throws IOException {
Socket server = null;
try {
server = new Socket(host, port);
} catch (UnknownHostException e) {
System.err.println(e);
System.exit(1);
}
stdIn = new BufferedReader(new InputStreamReader(System.in));
/* obtain an output stream to the server... */
PrintWriter out = new PrintWriter(server.getOutputStream(), true);
/* ... and an input stream */
BufferedReader in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
nick = getNick(in, out);
/* create a thread to asyncronously read messages from the server */
ServerConn sc = new ServerConn(server);
Thread t = new Thread(sc);
t.start();
String msg;
/* loop reading messages from stdin and sending them to the server */
while ((msg = stdIn.readLine()) != null) {
out.println(msg);
}
}
}
class ServerConn implements Runnable {
private BufferedReader in = null;
public ServerConn(Socket server) throws IOException {
/* obtain an input stream from the server */
in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
}
public void run() {
String msg;
try {
/* loop reading messages from the server and show them
* on stdout */
while ((msg = in.readLine()) != null) {
System.out.println(msg);
}
} catch (IOException e) {
System.err.println(e);
}
}
}

这里是 ChatServer.java:

    /* ChatServer.java */
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Hashtable;

public class ChatServer {

private static int port = 5000; /* port to listen on */

public static void main (String[] args) throws IOException
{
    ServerSocket server = null;

    try {
            server = new ServerSocket(port); /* start listening on the port */

        } catch (IOException e) {

System.err.println("Could not listen on port: " + port);
System.err.println(e);
System.exit(1);
}

Socket client = null;

while(true) {
try {

client = server.accept();

} catch (IOException e) {

System.err.println("Accept failed.");
System.err.println(e);
System.exit(1);
}

/* start a new thread to handle this client */
Thread t = new Thread(new ClientConn(client));
t.start();
}
}
}


class ChatServerProtocol {

private String nick;
private ClientConn conn;

/* a hash table from user nicks to the corresponding connections */
private static Hashtable<String, ClientConn> nicks =
new Hashtable<String, ClientConn>();

private static final String msg_OK = "OK";
private static final String msg_NICK_IN_USE = "NICK IN USE";
private static final String msg_SPECIFY_NICK = "SPECIFY NICK";
private static final String msg_INVALID = "INVALID COMMAND";
private static final String msg_SEND_FAILED = "FAILED TO SEND";

/**
* Adds a nick to the hash table
* returns false if the nick is already in the table, true otherwise
*/

private static boolean add_nick(String nick, ClientConn c) {

if (nicks.containsKey(nick)) {
return false;
} else {
nicks.put(nick, c);
return true;

}
}

public ChatServerProtocol(ClientConn c) {
nick = null;
conn = c;
}
private void log(String msg) {
System.err.println(msg);
}
public boolean isAuthenticated() {
return ! (nick == null);
}
/**
* Implements the authentication protocol.
* This consists of checking that the message starts with the NICK command
* and that the nick following it is not already in use.
* returns:
* msg_OK if authenticated
* msg_NICK_IN_USE if the specified nick is already in use
* msg_SPECIFY_NICK if the message does not start with the NICK command
*/
private String authenticate(String msg) {
if(msg.startsWith("NICK")) {
String tryNick = msg.substring(5);
if(add_nick(tryNick, this.conn)) {
log("Nick " + tryNick + " joined.");
this.nick = tryNick;
return msg_OK;
} else {
return msg_NICK_IN_USE;
}
} else {
return msg_SPECIFY_NICK;
}
}
/**
* Send a message to another user.
* @recepient contains the recepient's nick
* @msg contains the message to send
* return true if the nick is registered in the hash, false otherwise
*/
private boolean sendMsg(String recipient, String msg) {
if (nicks.containsKey(recipient)) {
ClientConn c = nicks.get(recipient);
c.sendMsg(nick + ": " + msg);
return true;
} else {
return false;
}
}
/**
* Process a message coming from the client
*/
public String process(String msg) {
if (!isAuthenticated())
return authenticate(msg);
String[] msg_parts = msg.split(" ", 3);
String msg_type = msg_parts[0];
if(msg_type.equals("MSG")) {
if(msg_parts.length < 3) return msg_INVALID;
if(sendMsg(msg_parts[1], msg_parts[2])) return msg_OK;
else return msg_SEND_FAILED;
} else {
return msg_INVALID;
}
}
}

class ClientConn implements Runnable {

private Socket client;
private BufferedReader in = null;
private PrintWriter out = null;

ClientConn(Socket client) {

this.client = client;

try {
/* obtain an input stream to this client ... */
in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
/* ... and an output stream to the same client */
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.err.println(e);
return;
}
}

public void run() {
String msg, response;
ChatServerProtocol protocol = new ChatServerProtocol(this);
try {
/* loop reading lines from the client which are processed
* according to our protocol and the resulting response is
* sent back to the client */
while ((msg = in.readLine()) != null) {
response = protocol.process(msg);
out.println("SERVER: " + response);
}
} catch (IOException e) {
System.err.println(e);
}
}

public void sendMsg(String msg) {
out.println(msg);
}
}

现在,鉴于我已经设置了物理连接(TCP/IP),我应该怎么做才能从两台计算机上运行这两个文件??

提前谢谢... :)

【问题讨论】:

    标签: java client-server chat


    【解决方案1】:

    听起来很可能是防火墙问题。您是否尝试在防火墙中为 1001 端口打开一个洞?

    【讨论】:

    • 我确实猜到了,并通过我的具有 windows XP 操作系统的计算机添加了端口 1001,但是,由于缺乏对 windows 7 的知识/经验,这是我朋友的计算机,我找不到一种在他的端口上添加端口的方法,我是否必须在两台计算机上都这样做以及 IP 地址如何,如果你能解释一下将有很大帮助的程序...谢谢
    • 您还应该使用 1024 以上的端口。因为这些端口通常用于系统进程和知名服务。
    • @Niaz:至少,您必须在每台充当服务器的计算机上执行此操作。不过,目前尚不清楚“IP 地址如何”是什么意思。我刚刚看到您已经将“localhost”硬编码到您的客户端代码中......当您想连接到另一台计算机时,这显然不起作用。
    • @PeterT,感谢您提供的信息,因为我只是一个帮助很大的初学者。 @Jon Skeet:这里发布的代码是我在本地计算机上尝试的版本,这就是为什么我提到“IP地址”并且不确定我应该将客户端的IP和服务器的IP放在哪里?跨度>
    • @Niaz:在 ChatClient 中,你有“localhost”,你应该有服务器 IP 地址。请注意,您实际上已经发布了两次 ChatClient,因此我们看不到 ChatServer 代码...
    【解决方案2】:

    您是否还查看了您的 java.policy 并确保它已配置为允许本地代码库打开套接字?

    【讨论】:

    • 不,我没有也不知道该怎么做
    • 你能解释一下这个'java.policy'吗?
    • 抱歉,我有一段时间没上网了。查看您的JRE/lib/security/java.policy,您需要确保您有权侦听该端口(我认为默认情况下它只允许超过 1024 的端口)并且还需要确保您对代码库具有连接权限。此链接适用于 JDK 1.4,但仍然适用:download.oracle.com/javase/1.4.2/docs/guide/security/…
    【解决方案3】:

    正如评论中提到的,您不应该为您的应用程序使用端口 1)如果你得到连接被拒绝,那么你应该正确检查异常,客户端程序在生成异常之前是否需要时间(这意味着请求将发送到服务器然后它给出连接被拒绝),在这种情况下你应该尝试 java.policy
    将以下内容放入名为 java.policy 的文件中

    授予{
    权限 java.net.SocketPermission ":1024-65535", “连接,接受”;
    权限 java.net.SocketPermission "
    :80", "connect";
    权限 java.io.FilePermission "", "read,write,delete";
    权限 java.security.SecurityPermission "
    ";
    };
    在编译时使用这个标志-Djava.security.policy=java.policy
    此外,您还应该尝试 -Djava.rmi.server.hostname=IP,其中 IP 是 client.java 的 clien-ip 和 server.java 的 server-ip

    2)如果您立即在客户端遇到异常,那么您的请求不会超出您的电脑,因此客户端有一些问题。
    正确检查异常并将其发布到此处。

    3) 虽然我没有遇到拒绝访问错误,但它似乎有端口问题,可以使用策略或端口>1024 解决。
    发布你现在得到了什么。

    【讨论】:

    • 非常感谢您提供的详细信息,不幸的是,我在家里,没有其他可以连接的电脑,我会尽快按照您所说的进行并发布这里的更新。顺便说一句,“-Djava.rmi.server.hostname=IP”——你提到 IP 是 client-ip 和 server-ip,所以我是否将 -Djava.rmi.client.hostname=IP 用于 ChatClient.java?
    • 还有一件事,在这个程序中,我没有使用rmi,所以我必须使用它然后执行你所说的编译指令吗??
    • 哦,如果你的连接被拒绝,那么你应该使用类似于 rmi 的东西(不知道是什么),但你没有使用 rmi,所以你不应该。
    • 这些东西真的是我在这里学习的好东西,我不会光看书和用java写代码来学习的,谢谢大家给我这些新材料,让我加强我的知识
    猜你喜欢
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多