总结
唉,题很简单,先是卡在了从客户端读取数据上,开始用的BufferedReader,最后反编译GUIClient.jar才知道用的是DataOutputStream,然后犯了致命的错误:java字符串比较用了==,应该用equals方法啊啊啊,
题意
Exam 1 TCP Chat Server
1 实验题目
根据题目下文给出的聊天协议列表,使用Java sockets实现一个简单的TCP聊天服务器。该服务器应该具有以下功能:
1. 从每一个客户端(client)读取信息;
2. 能将读取的信息转发给所有客户端;
3. 通过命令行获得端口(port)信息;
4. 监听特定端口(port)的请求信息;
5. 能够处理并发连接,即需要使用多线程来处理每一个连接。
题中已经提供了一个图形化客户端GUIClient.jar,可以使用它来连接你的聊天服务器。在命令行中(cmd)使用下面的命令运行这个jar文件:
java –jar GUIClient.jar<hostname> <port> <alias>
上述命令中,<hostname>是服务器运行所在的主机名,<port>是服务器的端口号,<alias>是客户端发送消息时在聊天系统上的昵称。运行出来时结果如下图所示:
2 消息协议
1. 从客户端到服务器的消息
服务器端接收客户端发送的下述格式的消息:
type^alias@hostip^target^message^
其中: type表示消息类型;
alias为该用户的昵称;
hostip为客户端主机的IP地址
target表示消息发动的目标地址
message为发送的消息内容。
消息中若某项无内容则用减号(-)表示;针对本次考试,协议中的target不做处理;消息类型type包含以下几种:
l m,发送给其他用户的聊天内容
例如:m^ZhanSan@10.130.7.62^-^Hi,I’m zhangsan^
l j,用户加入聊天时向服务器发送该类型的消息,此时message为空
例如:j^LiSi@10.130.7.63^-^-^
l p,用户退出时向服务器发送该类型的消息,此时message为空
例如:p^WangWu@10.130.7.64^-^-^
2. 从服务器到客户端的消息
服务器接收到m类型的消息时,直接将其转发给其他用户;
接收到j类型的消息时,向其他用户发送如下格式的消息:
m^Server@10.130.7.1^-^Lisihas joined from 10.130.7.63 (12:42 PM)^
服务器接收到p类型的消息时,向其他用户发送如下格式的消息:
m^Server@10.130.7.1^-^WangWu has parted from 10.130.7.64 (12:45 PM)^
3 实验要求
1) 按上述所给的消息格式完成ChatServer.java,实现客户端连接服务器向其他用户发送聊天消息,退出服务等相关操作。
2) 按考试要求提交
ChatServer.java
README file
将上述文件打包命名为:学号_姓名.rar 提交至ftp://10.128.48.10/相应目录下;
3) 所写的代码应符合Java编程规范,且应有必要的注释。
代码:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
public class Server {
/**
* @param args
* @author yzjyzjyzj杨宗军
* @date 2015/05/29
*/
ServerSocket serverSocket;
private final int PORT = 6666;// 这里端口号0~65535,但1~1023已经被系统占用了,应使用1024~65535之间的端口号,避免发生冲突。
//List<Socket> list= new ArrayList<Socket>();
//存放所有socket对象的输出流,以便于广播消息
List<DataOutputStream> listDop = new ArrayList<DataOutputStream>();
public Server() throws IOException {
serverSocket = new ServerSocket(PORT);
System.out.println("服务器创建成功");
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
new Server().service();
}
public void service() {
//int cnt = 1;
while (true) {
Socket socket = null;
try {
socket = serverSocket.accept();
// System.out.println("新的客户端创建成功! " + "客户端编号" + (cnt++) + ": "
// + socket.getInetAddress() + ": " + socket.getPort());
Thread work = new Thread(new Handler(socket)); // 为客户连接创建工作线程
work.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Handler implements Runnable { // 负责与单个客户通信的线程
private Socket socket;
// BufferedReader br;
// BufferedWriter bw;
// PrintWriter pw;
DataInputStream dip;
DataOutputStream dop;
Date dt = new Date();//获取当前时间
public Handler(Socket socket) {
this.socket = socket;
}
public void initStream() throws IOException { // 初始化输入输出流对象方法
// br = new BufferedReader(new InputStreamReader(socket
// .getInputStream()));
// bw = new BufferedWriter(new OutputStreamWriter(socket
// .getOutputStream()));
// pw = new PrintWriter(bw, true);
//输入输出流
dip = new DataInputStream(socket.getInputStream());
dop = new DataOutputStream(socket.getOutputStream());
}
@SuppressWarnings("deprecation")
public void run() { // 执行的内容
try {
initStream(); // 初始化输入输出流对象
String info = null;
//System.out.println("hello");
listDop.add(dop);//将此次创建的socket对象的DataOutputStream加入到列表中
while (null != (info = dip.readUTF())) {
//System.out.println("he");
String type = null;
String alias = null;
String hostip = null;
String target = null;
String message = null;
//字符串解析,用^作为分隔符
StringTokenizer tokenizer = new StringTokenizer(info, "^");
type = tokenizer.nextToken();
alias = tokenizer.nextToken();
hostip = tokenizer.nextToken();
if(tokenizer.hasMoreTokens()){
target = tokenizer.nextToken();
}
if(tokenizer.hasMoreTokens()){
message = tokenizer.nextToken();
}
//System.out.println("h" + type + "e");
//System.out.println("h" + type + alias + hostip + target+message);
if(type.startsWith("j")){
//服务器端自己先输出信息
System.out.println("m^Server@" + serverSocket.getInetAddress() + "^-^"
+ alias + " has joined from " + hostip + dt + "^");
//将消息传给其他所有客户端
//ArrayList<Socket>::Iterator it = new
for(int i = 0; i < listDop.size(); i++){
listDop.get(i).writeUTF("m^Server@" + serverSocket.getInetAddress() + "^-^"
+ alias + " has joined from " + hostip + dt +"^");
}
// //服务器端
// dop.writeUTF("m^Server@" + serverSocket.getInetAddress() + "^-^"
// + alias + " has joined from " + hostip + dt +"^");
}
else if(type.startsWith("m")){
//服务器端自己先输出信息
System.out.println("m^" + alias + "@" + hostip + "^-^" + message + "^");
//将消息传给其他所有客户端
for(int i = 0; i < listDop.size(); i++){
listDop.get(i).writeUTF("m^" + alias + "@" + hostip + "^-^" + message + "^");
}
// dop.writeUTF("m^" + alias + "@" + hostip + "^-^" + message + "^");
}
else if(type.startsWith("p")){
//服务器端自己先输出信息
System.out.println("m^Server@" + serverSocket.getInetAddress() + "^-^"
+ alias + " has parted from " + hostip + dt + "^");
//将消息传给其他所有客户端
for(int i = 0; i < listDop.size(); i++){
listDop.get(i).writeUTF("m^Server@" + serverSocket.getInetAddress() + "^-^"
+ alias + " has parted from " + hostip + dt + "^");
}
// dop.writeUTF("m^Server@" + serverSocket.getInetAddress() + "^-^"
// + alias + " has parted from " + hostip + dt + "^");
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != socket) {
try {
listDop.remove(dop);//从列表中删除DataOutputStream然后关闭socket
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}