JAVA入门学习(十五)——TCP编程(编写一个小型多人聊天系统)

本次共分为11个版本:

任务1-v1:代码修正

1.定义成员变量套接字
 2.在构造方法中初始化
 3.start方法处理读写
 4.main方法创建对象,调用start方法
----------------------------------------------------------
任务2-v2:

1.控制台一对一对话
 2.在客户端实现控制台输入
----------------------------------------------------------
任务3-v3:

1.一个客户端和服务器多次会话
2.客户端使用while循环输入
3.服务器端使用while循环接收数据
--------------------------------------------------------
任务4-v4:实现多线程的服务端

1.服务器端实现线程处理客户端请求
   定义线程
   private class ClientHandler implements Runnable{
	//定义Socket 变量
        public ClientHandler(Socket socket){
		//初始化成员变量
	}
	public void run() {
              //实现读写功能
	}
   }
2.让服务可以接受多客户端的请求
------------------------------------------------------------
任务5-v5:实现群聊
1.服务器端
       定义存放所有客户端输出流对象的数组
	//存放所有的客户端的输出流对象
	private PrintWriter[] allOut;
	构造方法中初始化
	serverSocket  = new ServerSocket(8888);
	//初始化
	allOut = new PrintWriter[0]; 
	在响应客户端数据时,遍历数组的输出流

2.客户端
	定义线程,负责接收服务器的响应信息,实现对写分离
---------------------------------------------------------
任务6-v6:实现窗口
任务7-v7:读写对象 
   1)把客户端和服务器端的输入输出流改为对象的输入输出流
	ObjectInputStream和ObjectOutputStream
   2)定义工具类
	public class Info{
		//0表示群聊;1表示上线,2表示下线,3表示私聊
		private int type;
		private String name;
		private String sendInfo;
	}
   3)客户端发送信息为Info对象,服务器响应信息为Info对象
------------------------------------------------------------- 
任务v8-v8:添加登录的窗口,根据登录名称显示用户姓名
--------------------------------------------------------------
任务v9-v9:显示在线列表
   1.在Info类中定义存放登录名的数组变量,添加set/get方法

   2.在服务器类中定义存放登录名的数组,构造方法中初始化,
     run方法中进行数组的扩容
   3.客户端发送的type=1,响应对象把登录人的数组传递给响应对象放回给客户端

   4.客户端登录成功,发送type=1的请求

   5.控制台测试。。。。。

   6.在窗口中添加在线列表组件,显示在线人的姓名
---------------------------------------------------------------
任务10-v10:下线
1)添加窗口的关闭处理事件,在关闭窗口的事件处理方法中发送
	type= 2的下线请求
2)服务器端代码调整,重新给数组赋值,数组中不包含下线的姓名
	把数组返回给客户端
3)客户端的响应信息代码调整,参照上线处理
--------------------------------------------------------------
第十一个任务:单聊
1)在右侧选择单聊的对象,使用list的selected事件处理
//列表的选中事件,(此代码写下窗口事件的后边)
 list.addListSelectionListener(new ListSelectionListener() {
	 public void valueChanged(ListSelectionEvent e) {
		//name表示单聊的那个对象的名字(name声明为成员变量)
		name = list.getSelectedValue();
	}
 });
2)在发送按钮的事件处理方法中进行处理(源代码需要重新调整)
	判断name!=null,那么发送type=3的单聊请求
	Info info = new Info(3,name,tfName.getText());
	否则发送的是群聊。
	参考代码如下:
	
3)在服务器端处理type=3的的请求处理
	通过name找到单聊的客户端的输出流;allOut={oos1,oos2}
	通过oos找到当前客户的名字                  onlines={name1,name2}
	响应请求对象Info:
 	参考代码如下:
	
4)客户端响应信息处理
	同群聊处理

🔺v1:

package com.rjxy.TCP.v1;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 *  1.定义成员变量套接字
 	2.在构造方法中初始化
 	3.start方法处理读写
 	4.main方法创建对象,调用start方法
 * @author 陶沅玱
 *
 */
public class Client {

	//1.创建套接字对象
	private Socket socket;	
	public Client() {
		try {
			//实例化套接字对象
			socket = new Socket("localhost", 6666);
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}	
	public void start() throws Exception {
		//2.对服务器发出请求
		OutputStream os = socket.getOutputStream();
		//打印流
		PrintWriter pw = new PrintWriter(os);
		pw.println("hello");
		pw.flush();		
		//3.接受服务器的响应
		InputStream is = socket.getInputStream();
		//把字节流转换成字符流输出到控制台上
		BufferedReader bw = new BufferedReader(
				new InputStreamReader(is));		
		//输出全部信息
		String str = bw.readLine();
		System.out.println(str);		
		//关闭流
		bw.close();
		is.close();
		pw.close();
		os.close();
		socket.close();
	}
	
	public static void main(String[] args) throws Exception {
		new Client().start();
	}
}

package com.rjxy.TCP.v1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *  1.定义成员变量套接字
 	2.在构造方法中初始化
 	3.start方法处理读写
 	4.main方法创建对象,调用start方法
 * @author 陶沅玱
 *
 */
public class Server {

	//1.定义套接字对象
	private ServerSocket serverSocket;
	
	public Server() {
		try {
			//实例化套接字对象
			serverSocket = new ServerSocket(6666);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//创建strat方法处理读写
	public void start() throws Exception {
		
		//2.接受客户端的请求
		System.out.println("等待客户端输入:");
		Socket socket = serverSocket.accept();
		System.out.println("客户端完成输入:");
		
		//3.创建输入流,读数据
		InputStream is = socket.getInputStream();
		//把字节流转换成字符流读出
		BufferedReader br = new BufferedReader(
				new InputStreamReader(is));
		//成功读取数据
		String str = br.readLine();
		System.out.println(str);
		
		//完成服务器的响应
		str = "服务器:" + str;
		
		//4.创建输出流,写操作
		OutputStream os = socket.getOutputStream();
		//打印流
		PrintWriter pw = new PrintWriter(os);
		
		//完成服务器的响应
		pw.println(str);
		pw.flush();
		
		//5.关闭流
		pw.close();
		os.close();
		br.close();
		is.close();
		socket.close();
		serverSocket.close();
	}
	
	public static void main(String[] args) throws Exception {
		new Server().start();
	}
	
}


🔺v2:

package com.rjxy.TCP.v2;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client {

	//1.定义套接字对象
	private Socket socket;
	
	public Client() {
		try {
			socket = new Socket("localhost", 6666);
		}  catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void start() throws Exception {
		//2.创建输出流,完成对服务器的请求
		OutputStream os = socket.getOutputStream();
		//利用打印流输出
		PrintWriter pw = new PrintWriter(os);
		
		//从键盘获取数据
		Scanner sc = new Scanner(System.in);
		System.out.print("Input");
		String str = sc.next();
		
		//给服务器发出请求
		pw.println(str);
		pw.flush();
		
		//3.创建输入流,接受服务器的响应,并在控制台打印输出
		InputStream is = socket.getInputStream();
		//把字节流转换成字符流,方便打印
		BufferedReader bw = new BufferedReader(
				new InputStreamReader(is));
		String msg = bw.readLine();
		System.out.println(msg);
		
		//4.关闭流
		bw.close();
		is.close();
		pw.close();
		os.close();
		socket.close();
	}
	
	public static void main(String[] args) throws Exception {
		new Client().start();
	}
}

package com.rjxy.TCP.v2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

	//1.定义套接字对象
	private ServerSocket serverSocket;
	
	public Server(){
		try {
			//实例化套接字对象
			serverSocket = new ServerSocket(6666);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void start() throws Exception {
		//2.建立与客户端的连接
		System.out.println("等待客户端的请求:");
		Socket socket = serverSocket.accept();
		System.out.println("成功接受客户端的请求!");
		
		//3.创建输入流,接受客户端的数据
		InputStream is = socket.getInputStream();
		//将字节流转换成字符流
		BufferedReader br = new BufferedReader(
				new InputStreamReader(is));
		//接收到数据
		String str = br.readLine();
		System.out.println(str);
		//完成服务器的响应
		str = "服务器:   " + str;
		
		//4.创建输出流,完成对客户端的响应
		OutputStream os = socket.getOutputStream();
		PrintWriter pw = new PrintWriter(os);
		pw.println(str);
		pw.flush();
		
		//5.关闭
		pw.close();
		os.close();
		br.close();
		is.close();
		socket.close();
		serverSocket.close();
	}	
	public static void main(String[] args) throws Exception {
		new Server().start();
	}
}

🔺v3:

package com.rjxy.TCP.v3;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

/**
 * 
	1.一个客户端和服务器多次会话
	2.客户端使用while循环输入
	3.服务器端使用while循环接收数据
 * @author 陶沅玱
 *
 */
public class Client {

	//1.定义套接字对象
	private Socket socket;
	
	public Client() {
		try {
			socket = new Socket("localhost", 6666);
		}  catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void start() throws Exception {
		
		OutputStream os;
		PrintWriter pw;
		
		InputStream is;
		BufferedReader br;
		
		while(true) {
			
			//2.创建输出流,完成对服务器的请求
			os = socket.getOutputStream();
			//利用打印流输出
			pw = new PrintWriter(os);
			
			//从键盘获取数据
			Scanner sc = new Scanner(System.in);
			System.out.print("Input");
			String str = sc.next();
			
			//给服务器发出请求
			pw.println(str);
			pw.flush();
			
			//3.创建输入流,接受服务器的响应,并在控制台打印输出
			is = socket.getInputStream();
			//把字节流转换成字符流,方便打印
			br = new BufferedReader(
					new InputStreamReader(is));
			String msg = br.readLine();
			System.out.println(msg);
		}
		
		
		//因为设置的是死循环,所以不用关闭流
		//4.关闭流
//		bw.close();
//		is.close();
//		pw.close();
//		os.close();
//		socket.close();
	}
	
	public static void main(String[] args) throws Exception {
		new Client().start();
	}
}

package com.rjxy.TCP.v3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 
	1.一个客户端和服务器多次会话
	2.客户端使用while循环输入
	3.服务器端使用while循环接收数据
	
 * @author 陶沅玱
 *
 */
public class Server {

	//1.定义套接字对象
	private ServerSocket serverSocket;
	
	public Server(){
		try {
			//实例化套接字对象
			serverSocket = new ServerSocket(6666);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void start() throws Exception {
		//2.建立与客户端的连接
		System.out.println("等待客户端的请求:");
		Socket socket = serverSocket.accept();
		System.out.println("成功接受客户端的请求!");
		
		InputStream is;
		BufferedReader br;
		
		OutputStream os;
		PrintWriter pw;
		
		while(true) {
			//3.创建输入流,接受客户端的数据
			is = socket.getInputStream();
			//将字节流转换成字符流
			br = new BufferedReader(
					new InputStreamReader(is));
			//接收到数据
			String str = br.readLine();
			System.out.println(str);
			//完成服务器的响应
			str = "服务器:   " + str;
			
			//4.创建输出流,完成对客户端的响应
			os = socket.getOutputStream();
			pw = new PrintWriter(os);
			pw.println(str);
			pw.flush();
		}
		
		//5.关闭
//		pw.close();
//		os.close();
//		br.close();
//		is.close();
//		socket.close();
//		serverSocket.close();
	}
	
	public static void main(String[] args) throws Exception {
		new Server().start();
	}
	
}

🔺v4:

package com.rjxy.TCP.v4;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

/**
 * 	服务器实现多线程
 * @author 陶沅玱
 *
 */
public class Client {

	//1.定义套接字对象
	private Socket socket;
	
	public Client() {
		try {
			socket = new Socket("localhost", 6666);
		}  catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void start() throws Exception {
		
		OutputStream os;
		PrintWriter pw;
		
		InputStream is;
		BufferedReader br;
		
		while(true) {
			
			//2.创建输出流,完成对服务器的请求
			os = socket.getOutputStream();
			//利用打印流输出
			pw = new PrintWriter(os);
			
			//从键盘获取数据
			Scanner sc = new Scanner(System.in);
			System.out.print("Input");
			String str = sc.next();
			
			//给服务器发出请求
			pw.println(str);
			pw.flush();
			
			//3.创建输入流,接受服务器的响应,并在控制台打印输出
			is = socket.getInputStream();
			//把字节流转换成字符流,方便打印
			br = new BufferedReader(
					new InputStreamReader(is));
			String msg = br.readLine();
			System.out.println(msg);
		}
		
		
		//因为设置的是死循环,所以不用关闭流
		//4.关闭流
//		bw.close();
//		is.close();
//		pw.close();
//		os.close();
//		socket.close();
	}

	
	public static void main(String[] args) throws Exception {
		new Client().start();
	}
}

package com.rjxy.TCP.v4;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务器实现多线程
 * 
 * @author 陶沅玱
 *
 */
public class Server {

	// 1.定义套接字对象
	private ServerSocket serverSocket;

	public Server() {
		try {
			// 实例化套接字对象
			serverSocket = new ServerSocket(6666);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void start() throws Exception {
		while(true) {			
			// 2.建立与客户端的连接
			System.out.println("等待客户端的请求:");
			Socket socket = serverSocket.accept();
			System.out.println("成功接受客户端的请求!");
			
			// 开启多线程
			new Thread(new ServerThread(socket)).start();
		}

		// 5.关闭
//		pw.close();
//		os.close();
//		br.close();
//		is.close();
//		socket.close();
//		serverSocket.close();
	}

	// 实现服务器的多线程,可以同时会话多个客户端
	private class ServerThread implements Runnable {

		Socket socket;

		public ServerThread(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			InputStream is;
			BufferedReader br;

			OutputStream os;
			PrintWriter pw;

			while (true) {
				try {
					// 3.创建输入流,接受客户端的数据
					is = socket.getInputStream();
					// 将字节流转换成字符流
					br = new BufferedReader(new InputStreamReader(is));
					// 接收到数据
					String str = br.readLine();
					System.out.println(str);
					// 完成服务器的响应
					str = "服务器:   " + str;

					// 4.创建输出流,完成对客户端的响应
					os = socket.getOutputStream();
					pw = new PrintWriter(os);
					pw.println(str);
					pw.flush();

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
		}

	}

	public static void main(String[] args) throws Exception {
		new Server().start();
	}

}

🔺v5:

package com.rjxy.TCP.v5;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

/**
 * 	任务5-v5:实现群聊
   1.服务器端
       定义存放所有客户端输出流对象的数组
	//存放所有的客户端的输出流对象
	private PrintWriter[] allOut;
	构造方法中初始化
	serverSocket  = new ServerSocket(8888);
	//初始化
	allOut = new PrintWriter[0]; 
	在响应客户端数据时,遍历数组的输出流

   2.客户端
	定义线程,负责接收服务器的响应信息,实现对鞋分离
 * @author 陶沅玱
 *
 */
public class Client {

	//1.定义套接字对象
	private Socket socket;
	
	public Client() {
		try {
			socket = new Socket("localhost", 6666);
		}  catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void start() throws Exception {
		
		OutputStream os;
		PrintWriter pw;
		
		while(true) {
			
			//开启多线程
			new Thread(new ClientThread(socket)).start();
			
			//2.创建输出流,完成对服务器的请求
			os = socket.getOutputStream();
			//利用打印流输出
			pw = new PrintWriter(os);
			
			//从键盘获取数据
			Scanner sc = new Scanner(System.in);
			System.out.print("Input");
			String str = sc.next();
			
			//给服务器发出请求
			pw.println(str);
			pw.flush();

		}
		
		
		//因为设置的是死循环,所以不用关闭流
		//4.关闭流
//		bw.close();
//		is.close();
//		pw.close();
//		os.close();
//		socket.close();
	}

	//定义线程,监听服务器输出的全部消息
	//因此,只用把输入流放到线程即可
	private class ClientThread implements Runnable{

		Socket socket;
		
		InputStream is;
		BufferedReader br;
		
		public ClientThread(Socket socket) {
			this.socket = socket;
		}
		
		@Override
		public void run() {
			try {
				
				//3.创建输入流,接受服务器的响应,并在控制台打印输出
				is = socket.getInputStream();
				//把字节流转换成字符流,方便打印
				br = new BufferedReader(
						new InputStreamReader(is));
				String msg = br.readLine();
				System.out.println(msg);
				
			}catch(Exception e) {
				
			}
		}
	}
	
	public static void main(String[] args) throws Exception {
		new Client().start();
	}
}

package com.rjxy.TCP.v5;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

/**
 * 	任务5-v5:
 * 1.实现群聊 1.服务器端 定义存放所有客户端输出流对象的数组 //存放所有的客户端的输出流对象 private PrintWriter[] allOut; 
 * 	构造方法中初始化 serverSocket = new ServerSocket(8888); 
 * 	初始化 allOut = new PrintWriter[0]; 
 * 	在响应客户端数据时,遍历数组的输出流
 * 2.客户端 定义线程,负责接收服务器的响应信息,实现对鞋分离
 * 
 * @author 陶沅玱
 *
 */
public class Server {

	// 1.定义套接字对象
	private ServerSocket serverSocket;

	// 定义存放所有客户端输出流对象的数组
	private PrintWriter[] allOut = {};

	public Server() {
		try {
			// 实例化套接字对象
			serverSocket = new ServerSocket(6666);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void start() throws Exception {
		while (true) {
			// 2.建立与客户端的连接
			System.out.println("等待客户端的请求:");
			Socket socket = serverSocket.accept();
			System.out.println("成功接受客户端的请求!");

			// 开启多线程
			new Thread(new ServerThread(socket)).start();
		}

		// 5.关闭
//		pw.close();
//		os.close();
//		br.close();
//		is.close();
//		socket.close();
//		serverSocket.close();
	}

	// 实现服务器的多线程,可以同时会话多个客户端
	private class ServerThread implements Runnable {
		
		Socket socket;

		public ServerThread(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				InputStream is;
				BufferedReader br;

				OutputStream os;
				PrintWriter pw;

				// 3.创建输入流,接受客户端的数据
				is = socket.getInputStream();

				// 将字节流转换成字符流
				br = new BufferedReader(new InputStreamReader(is));

				// 4.创建输出流,完成对客户端的响应
				os = socket.getOutputStream();
				pw = new PrintWriter(os);

				// 将输出流对象存放到数组中
				// 先扩容
				allOut = Arrays.copyOf(allOut, allOut.length + 1);
				// 存放对象(即客户端)
				allOut[allOut.length - 1] = pw;

				while (true) {
					try {

						// 接收到数据
						String str = br.readLine();
						System.out.println(str);

						// 完成服务器的响应
						str = "服务器:   " + str;

						// allOut数组里面存放的所有输出流对象(客户端)都会收到这个消息
						for (PrintWriter p : allOut) {
							p.println(str);
							p.flush();
						}

					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

				}
			} catch (Exception e) {

			}
		}

	}

	public static void main(String[] args) throws Exception {
		new Server().start();
	}

}

▲v6:

package com.rjxy.TCP.v6;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;


/**
 * 实现窗口化群聊
 * 
 * @author 陶沅玱
 *
 */
public class Client extends JFrame {

	// 1.定义套接字对象
	private Socket socket;

	private PrintWriter pw = null;

	public Client() {
		build();
		try {
			socket = new Socket("localhost", 6666);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	// 创建窗口组件
	// 创建文本区
	JTextArea ta = new JTextArea();
	// 创建文本框
	JTextField tf = new JTextField(16);
	// 创建按钮
	JButton send = new JButton("发送");

	// 添加组件到窗口容器
	public void build() {
		this.add(ta, BorderLayout.CENTER);

		JPanel p = new JPanel();
		p.add(tf);
		p.add(send);
		this.add(p, BorderLayout.SOUTH);

		// 设置窗口的属性
		this.setTitle("聊天室");
		this.setSize(420, 300);
		this.setLocationRelativeTo(null);

		// 显示
		this.setVisible(true);

		// 完成send按钮的事件监听
		send.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				pw.println(tf.getText());
				pw.flush();
			}
		});
	}

public void start() {
		
		new Thread(new ClientThread(socket)).start();
		
		// 2.获取输出流,写信息
		OutputStream out;
		
		
		try {
			out = socket.getOutputStream();
			pw = new PrintWriter(out);
			
			Scanner sc = new Scanner(System.in);
//			while (true) {
//				从控制台输入获取信息
//				System.out.println("Input:");
//				String msg = sc.next();
//
//				pw.println(msg);
//				pw.flush();			
//			}

		} catch (IOException e) {
			e.printStackTrace();
		}
//			} finally {
//			// 4.关闭流
//			try {
//				
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//		}
	}

	// 定义线程,监听服务器输出的全部消息
	// 因此,只用把输入流放到线程即可
	private class ClientThread implements Runnable {

		Socket socket;

		InputStream is;
		BufferedReader br;

		public ClientThread(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			try {

				// 3.创建输入流,接受服务器的响应,并在控制台打印输出
				is = socket.getInputStream();
				// 把字节流转换成字符流,方便打印
				br = new BufferedReader(new InputStreamReader(is));
				String msg = br.readLine();
				System.out.println(msg);
				
				//打印到窗口中
				String str = "";
				while((str = br.readLine()) != null) {
					//System.out.println(msg);
					ta.append(str + "\n");
				}

			} catch (Exception e) {

			}
		}
	}

	public static void main(String[] args) throws Exception {
		new Client().start();
	}
}

package com.rjxy.TCP.v6;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

/**
 * 	实现窗口化群聊
 * @author 陶沅玱
 *
 */
public class Server {

	// 1.定义套接字对象
	private ServerSocket serverSocket;

	// 定义存放所有客户端输出流对象的数组
	private PrintWriter[] allOut = {};

	public Server() {
		try {
			// 实例化套接字对象
			serverSocket = new ServerSocket(6666);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void start() throws Exception {
		while (true) {
			// 2.建立与客户端的连接
			System.out.println("等待客户端的请求:");
			Socket socket = serverSocket.accept();
			System.out.println("成功接受客户端的请求!");

			// 开启多线程
			new Thread(new ServerThread(socket)).start();
		}

		// 5.关闭
//		pw.close();
//		os.close();
//		br.close();
//		is.close();
//		socket.close();
//		serverSocket.close();
	}

	// 实现服务器的多线程,可以同时会话多个客户端
	private class ServerThread implements Runnable {
		
		Socket socket;

		public ServerThread(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				InputStream is;
				BufferedReader br;

				OutputStream os;
				PrintWriter pw;

				// 3.创建输入流,接受客户端的数据
				is = socket.getInputStream();

				// 将字节流转换成字符流
				br = new BufferedReader(new InputStreamReader(is));

				// 4.创建输出流,完成对客户端的响应
				os = socket.getOutputStream();
				pw = new PrintWriter(os);

				// 将输出流对象存放到数组中
				// 先扩容
				allOut = Arrays.copyOf(allOut, allOut.length + 1);
				// 存放对象(即客户端)
				allOut[allOut.length - 1] = pw;

				while (true) {
					try {

						// 接收到数据
						String str = br.readLine();
						System.out.println(str);

						// 完成服务器的响应
						str = "服务器:   " + str;

						// allOut数组里面存放的所有输出流对象(客户端)都会收到这个消息
						for (PrintWriter p : allOut) {
							p.println(str);
							p.flush();
						}

					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

				}
			} catch (Exception e) {

			}
		}

	}

	public static void main(String[] args) throws Exception {
		new Server().start();
	}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值