使用多线程实现多个客户端与服务端通信1
Server.java
package socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 聊天室服务端
 * @author 小明
 *
 */
public class Server {
	/**
	 * 运行在服务端的ServerSocket主要有两个作用:
	 * 1:向系统申请服务端口,客户端就是通过这个端口与服务端建立连接的。
	 * 2:监听服务端口,一旦客户端与服务端建立连接,就会
	 * 自动创建一个Socket,并通过该Socket与建立连接的
	 * 客户端进行交互。
	 * 
	 */
	private ServerSocket server;
	
	public Server()
	{
		try{
			/**
			 * 实例化ServerSocket的同时要指定向系统申请的服务端口。注意,该端口
			 * 不能与当前系统其它应用程序申请的端口号一致,
			 * 否则会抛出端口被占用的异常。
			 */
			System.out.println("正在启动服务端...");
			server = new ServerSocket(8088);
			System.out.println("服务端启动完毕!");
		}catch(Exception e){
			
		}
	}
	
	public void start()
	{
		try {
			while(true)
			{
			System.out.println("等待客户端连接");
			Socket socket = server.accept();
			//accept用来感知socket。
			System.out.println("一个客户端连接进去了。");
			
			ClientHandler hander = new ClientHandler(socket);
			Thread t1 = new Thread(hander);
			t1.start();
			}
			/**
			 * 准备接受客户端连接
			 * 
			 * 这是一个阻塞方法。
			 *一旦调用accpet()方法,服务端阻塞在这里,等着客户端连接了。
			 *这时当我们启动客户端时,客户端实例化socket,通过IP找到应用程序。
			 *这时accpet()马上就会有反应。accpet()方法执行完就返回一个socket。
			 *通过这个socket就可以与刚建立连接的这个客户端进行通讯了。
			 *客户端创建一个socket,服务端通过accept()接收一个socket。
			 *这时候就可以进行沟通了。
			 * 需要处理异常。
			 */
  		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		Server server = new Server();
		server.start();
	}
	
	/**
	 * 通过输入流读取远端计算机发送过来的信息时
	 * br.readLine()方法对于不同系统的客户端断开时的反应不一样
	 * windows的客户端断开时,会直接抛出异常
	 * linux的客户端断开时,会返回null
	 * 该线程任务是负责与指定的客户端进行交互
	 * @author 小明
	 *
	 */
	private class ClientHandler implements Runnable{
		private Socket socket;
		private String host;
		//创建时需要将Socket传入,以便对该客户端交互
	    public ClientHandler(Socket socket) {
	    	this.socket = socket;
	    	//通过socket获取远端的地址信息
	    	InetAddress address = socket.getInetAddress();
	    	host = address.getHostAddress();
		}
		@Override
		public void run() {
			try{
				System.out.println("进入了线程,现在正在调用run()方法");
				InputStream in = socket.getInputStream();
				InputStreamReader isr = new InputStreamReader(in);
				BufferedReader br = new BufferedReader(isr);
				String message = null;
				System.out.println("客户端地址是:" + host);
				//System.out.println("尝试输出br.readLine()" + br.readLine());
				System.out.println("while最上面的那条语句");
				
				while((message = br.readLine()) != null)
				{
					System.out.println("读取到了数据");
					System.out.println(host + "说" + message);
					System.out.println("一个客户端连接了");
				}
				if(message == null){
					System.out.println("message是空的");
				}
				br.close();
			}catch(IOException e){
				e.printStackTrace();
			}finally{
				//br.close();
			}
		}
		
	}
	
}
Client.java
package socket;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/**
 * 聊天室客户端
 * @author 小明
 *
 */
public class Client {
	/**
	 * 套接字
	 * 封装了TCP协议的通信细节,让我们可以简单地使用它完成TCP通讯
	 * Socket连接后提供了两条流,通过两条流的读写操作完成与远端计算机的数据连接
	 * 完成与远端计算机的数据交换。
	 */
	private Socket socket;
	public Scanner reader;
	/**
	 * 用来初始化客户端
	 */
	public Client()
	{
		try {
			/**
			 * 实例化Socket时需要传入两个参数:
			 * 1:服务端的IP地址
			 * 2:服务端的端口号
			 * 通过IP地址可以找到服务端所在的计算机
			 * 通过端口可以找到运行在服务端计算机上的
			 * 服务端应用程序
			 * 注意,实例化Socket的过程就是连接的过程,若
			 * 连接失败就会抛出异常。
			 */
			reader = new Scanner(System.in);
			
			System.out.println("正在连接服务端...");
			socket = new Socket("localhost", 8088);
			System.out.println("与服务端建立连接!");
			
			/**
			 * 有两个参数,一个是IP地址,一个是端口号
			 */
			/**
			 * 所有应用程序在使用网络的时候都要和操作系统申请一个网络端口
			 * 
			 */
			/**
			 * 异常要我们自己进行处理,不要抛出
			 */
		}catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 写程序时不要过度依赖main方法
	 * 客户端开始工作的方法
	 */
	public void start()
	{
		try{
			//socket.getOutputStream();
			//打桩
			//可以找到代码错的地方。
			PrintWriter pw = new PrintWriter(
			new BufferedWriter(
			new OutputStreamWriter(
			socket.getOutputStream())), true);
			//pw.write("你好服务端");
			//使用上面这条语句是错的,要使用具有自动行刷新的方法
			//不要再下意识地写上面那条语句了
//			for(int i = 0; i < 10; i++){
//				pw.println("你好服务端!" + i);
//			}
			while(true)
			{
				String line = reader.nextLine();
				pw.println(line);
			}
			
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		Client client = new Client();
		client.start();
	}
	
}
                    
                
                
            
        
浙公网安备 33010602011771号