ssd8 网络与分布式系统实验 EXAM1

总结

唉,题很简单,先是卡在了从客户端读取数据上,开始用的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包含以下几种:

m,发送给其他用户的聊天内容

例如:m^ZhanSan@10.130.7.62^-^Hi,I’m zhangsan^

j,用户加入聊天时向服务器发送该类型的消息,此时message为空

例如:j^LiSi@10.130.7.63^-^-^

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();
					}
				}
			}
		}
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值