MultiTalkServer.java
package Chat3;
import java.net.InetAddress;
import java.io.*;
import java.net.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class MultiTalkServer{
boolean listening=true;
ServerSocket serverSocket = null;
static HashMaps hashmap = new HashMaps();
static int clientNumber = 0;
public static void main(String[]args) throws IOException {
new MultiTalkServer().start();
}
public void start() throws IOException{
try {
serverSocket = new ServerSocket(4700);
////创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口在端口4700监听客户请求
listening = true;
}catch(IOException e){
System.out.println("Couldnot listen on port:4700.");
//出错,打印出错信息
System.exit(-1); //退出
}
System.out.println("***服务器已经启动,等待客户端的连接***");
while(listening){ //循环监听等待客户端的连接
//监听到客户请求,根据得到的Socket对象和客户计数创建服务线程,并启动之
//调用accept()方法开始监听,等待客户端的连接
Socket socket = serverSocket.accept();//程序将在此等候客户端的连接
System.out.println("***客户端成功连接***");
clientNumber++;//记录客户数目
ServerThread serverThread= new ServerThread(socket,clientNumber,hashmap);////创建一个新的线程
new Thread(serverThread).start();//启动线程,调用start()方法后,线程类会自动调用run()方法
System.out.println("Online Client is " + clientNumber);
InetAddress address = socket.getInetAddress(); //获取IP
System.out.println("当前客户端的IP:"+address);//*
}
serverSocket.close(); //关闭ServerSocket
}
}
TalkClient.java
package Chat3;
import java.awt.BorderLayout;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.*;
import java.net.*;
public class TalkClient extends Frame implements Runnable, ActionListener{
//实现 ActionListener 接口,为动作监听接口,是Java swing 监听窗体动作的一个接口
//多线程实现方式---实现Runnable接口
//private String name;
//static int clientNumber = 0;
private TextField inputChat= new TextField();//输入区
//文本输入框 TextField
private TextArea showChat = new TextArea();//显示区
private MenuItem OPEN=new MenuItem("open file");//菜单构造
String prefix; //读取到的文件后缀名,读取以后和recv拼接,形成传输文件
Socket socket=null; //保存与本线程相关的Socket对象
private BufferedReader is = null;
private PrintWriter os = null;//两个流构造
TalkClient(Socket socket) throws IOException{
this.socket=socket;
this.is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.os=new PrintWriter(socket.getOutputStream());
//name="www";
//以下是图形用户界面的构造 //AWT
setLocation(1000, 100);
setSize(1000, 1000);
Menu file=new Menu("SEND FILE");
file.add(OPEN);//打开这个按钮
OPEN.setEnabled(true);
OPEN.addActionListener(this);//事件监听
MenuBar bar=new MenuBar();
bar.add(file);
setMenuBar(bar);
setSize(100,100);
setVisible(true);
add(inputChat, BorderLayout.SOUTH);//布局
add(showChat, BorderLayout.NORTH);//布局
pack();//依据放置的组件设定窗口的大小 使之正好能容纳放置的所有组件
inputChat.addActionListener(this);//窗口中输入,动作监听
// 注册监听器以监听事件源产生的事件
addWindowListener(new WindowAdapter() {//添加一个窗口,监听响应关闭按钮
public void windowClosing(WindowEvent e) ////这是窗口关闭事件
{
System.exit(0);//退出
}
});
setVisible(true); //可以运行开始画图
}
public void actionPerformed(ActionEvent e) {//定义处理事件的方法
String s =inputChat.getText().trim();// 获取inputchat的text属性,也就是按钮文字,trim()去除前后空格
inputChat.setText("");// 将取到的文本设置到一个输入框中
os.println(s);
os.flush();
if(e.getSource()==OPEN)//事件源是OPEN
{
FileDialog fd=new FileDialog(this,"open file",FileDialog.LOAD);//添加窗口
fd.setVisible(true);//FileDialog窗口构造
if(fd.getFile()!=null){
File file=new File(fd.getDirectory()+fd.getFile());
//创建了一个File对象,路径是directory,名字是filename。
//然后就可以调用这个对象的相关方法完成文件创建,删除,读取,写入等操作
String fileName=file.getName();
prefix=fileName.substring(fileName.lastIndexOf(".")+1);//这两行读取后缀名
if(file.exists())
try{
readFile(file.toString());
System.out.println(file.toString()+"\n\r");
} catch(IOException e1) {
e1.printStackTrace();
}
else
showChat.setText("Filename:"+file+" invalid");
}
fd.dispose();//资源释放
}
}
public void readFile(String file) throws IOException{
//读文件,并且刷入流中
String readline;
BufferedReader in = new BufferedReader(new FileReader(file));//读入多种格式文件
while((readline=in.readLine())!=null)
{
os.println(readline);
os.flush();//刷新输出流,使Server马上收到该字符串
//在系统标准输出上打印读入的字符串
System.out.println(readline);
}
}
public static void main(String[]args) throws UnknownHostException, IOException{
//向本机的4700端口发出客户请求
BufferedReader fis=null;
Socket socket=new Socket("127.0.0.1",4700);
//由系统标准输入设备构造BufferedReader对象
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
//由Socket对象得到输出流,并构造PrintWriter对象
PrintWriter os=new PrintWriter(socket.getOutputStream());
//由Socket对象得到输入流,并构造相应的BufferedReader对象
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
Thread tRecv = new Thread(new TalkClient(socket));
tRecv.start();
//以下是没有图形处理界面的一个线程,这里保留下来作为注释,也作为项目的一个进程记录
/*while(true)
{
String readline;
readline=sin.readLine();//从系统标准输入读入一字符串
while(!readline.equals("bye")){//若从标准输入读入的字符串为 "bye"则停止循环,将从系统标准输入读入的字符串输出到Server
os.println(readline);
os.flush();//刷新输出流,使Server马上收到该字符串
在系统标准输出上打印读入的字符串
System.out.println("Client:"+readline);
if(!readline.equals("file")){
//从Server读入一字符串,并打印到标准输出上
readline=sin.readLine();//从系统标准输入读入一字符串
}
else
fis=newBufferedReader(new FileReader("f:/test.txt"));//这里只有.txt文件
readline=fis.readLine();
System.out.println("1");
while((readline=fis.readLine())!=null)
{
System.out.println("2");
os.println(readline);
os.println('\r');
os.flush();//刷新输出流,使Server马上收到该字符串
//在系统标准输出上打印读入的字符串
System.out.println(readline);
//从Server读入一字符串,并打印到标准输出上
}//System.out.println("3");
readline=sin.readLine();//从系统标准输入读入一字符串
}
os.close(); //关闭Socket输出流
is.close(); //关闭Socket输入流
fis.close();
socket.close(); //关闭Socket
}
*/
}
public void run() {//文件操作启动线程,start方法启动run方法
//多线程实现方式---实现Runnable接口,在使用该方式实现时,使需要实现多线程的类实现Runnable,实现该接口需要覆盖run方法,
//然后将需要以多线程方式执行的代码书写在run方法内部或在run方法内部进行调用。
while(true)
{
try {
String ss=is.readLine();
showChat.append(ss +"\n\r");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*public void disconnect() {
try {
if (os != null)
os.close();
if(is !=null)
is.close();//关闭Socket输入流
if (socket!= null)
socket.close();
} catch (IOException e) {
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
}
}*/
}
DistributeThread.java
package Chat3;
public class DistributeThread extends Thread{
Stream stream1 = null;
Stream stream2 = null;
boolean flag = false;
public DistributeThread(Stream stream1, Stream stream2) {
this.stream1 = stream1; //消息流
this.stream2 = stream2;
flag = true;
}
public void run() {
try {
String line = null;
line = stream1.is.readLine();
while(!line.equals("bye")) {
stream1.os.println(stream1.name+":"+line);
stream1.os.flush();
stream2.os.println(stream1.name+":"+line);
stream2.os.flush();
System.out.println(stream1.name+":"+line);
line = stream1.is.readLine();
}
flag = false;
}catch(Exception e){
System.out.println("Error:"+e);
}
finally {
//MultiTalkServer.getnumber() ;
MultiTalkServer.clientNumber--;
System.out.println("Online Client is " +MultiTalkServer.clientNumber);
}
}
}
HashMaps.java
package Chat3;
import java.util.*;
public class HashMaps {
Map
public HashMaps(){ //初始化
hashmap = new HashMap
}
public void put(String key, Stream value){ //添加新成员
hashmap.put(key, value);
}
public Stream get(String key){ //通过key获取value
return hashmap.get(key);
}
public boolean containsKey(String key){ //判断可以是否存在
return hashmap.containsKey(key);
}
}
ServerThread.java
package Chat3;
import java.io.*;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.*;
public class ServerThread extends Thread {
//下面这个表储存链接的客户端的socket
Socket socket=null; //保存与本线程相关的Socket对象
HashMaps hashmap = null;
int clientNumber;
private BufferedReader is = null;
private PrintWriter os = null;
private BufferedReader sin=null;
public ServerThread(Socket s,int num,HashMaps hashmap) throws IOException{//构造函数
super();
this.socket=s;
clientNumber=num+1;//初始化clientNumber变量
this.hashmap=hashmap;//初始化socket变量
this.is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//由Socket对象得到输出流,并构造PrintWriter对象
this.os=new PrintWriter(socket.getOutputStream());//套接字的终端输出流写到网络中
//由系统标准输入设备构造BufferedReader对象
this.sin=new BufferedReader(new InputStreamReader(System.in));
}
public void run() { //线程主体
try{
//int n;
//n=MultiTalkServer.getnumber();
Stream S = new Stream(socket);
S.os.println("请输入你的姓名:");
S.os.flush();
S.name = S.is.readLine();
S.os.println(S.name);
S.os.flush();
hashmap.put(S.name, S);//存入客户端名称
S.os.println("请输入聊天对象:");
S.os.flush();
String line = S.is.readLine();
S.os.println(line);
S.os.flush();
while (!hashmap.containsKey(line)){
S.os.println("聊天对象不存在,请重新输入:");
S.os.flush();
line = S.is.readLine();
S.os.println(line);
S.os.flush();
continue;
}
//S.os.println(line);
Stream s = hashmap.get(line);
DistributeThread assign = new DistributeThread(S, s);
assign.start();
/*String str=S.is.readLine();
//在显示屏上输出客户端都入的字符串
System.out.println("Client "+socket.getInetAddress()+":"+str);//输出ip地址,这里可以改为客户端名称
/*for(int i = 0 ; i < MultiTalkServer.st.size(); i++){
ServerThread serverThread1= MultiTalkServer.st.get(i);
//serverThread1.send("Client"+MultiTalkServer.clientNumber+":"+str);
} */
//System.out.println("Online Client is " +n);
//}
}catch(Exception e){
System.out.println("Error:"+e);//出错,打印出错信息
}
//最初在线人数当关闭客户端时在这里进行了减一,但是因为两个客户端建立连接时写在了try语句块里,
//所以在这里加入Finally出口是错误的方式。
/*finally {
MultiTalkServer.clientNumber--;
System.out.println("Online Client is " +MultiTalkServer.clientNumber);}*/
}
}
Stream.java
package Chat3;
import java.io.*;
import java.net.*;
public class Stream {
Socket socket = null;
//用于发消息
BufferedReader sin = null;
PrintWriter os = null;
BufferedReader is = null;
//用于传文件
DataInputStream dis = null;
DataOutputStream dos = null;
String name = null;
boolean flag = false;
public Stream(Socket socket) throws Exception{
this.socket = socket;
sin=new BufferedReader(new InputStreamReader(System.in)); //通过键盘输入构造输入流
is=new BufferedReader(new InputStreamReader(socket.getInputStream())); //输入流,用于消息传输,字符串传输
os=new PrintWriter(socket.getOutputStream()); //输出流,用于消息传输,字符串传输
}
public void close() throws Exception{
dis.close();
dos.close();
is.close();
os.close();
socket.close();
}
}