zoukankan      html  css  js  c++  java
  • 命令行界面的C/S聊天室应用 (Socket多线程实现)

    命令行界面即在Eclipe控制台输入数据。

    服务器端包含多个线程,每个Socket对应一条线程,该线程负责读取对应输入流的数据(从客户端发送过来的数据),并将读到的数据向每个Socket输出流发送一遍(将一个客户端发送的数据"广播给其他客户端"),因此需要在服务器端使用List来保存所有的Socket.

    下面是服务器端的实现代码,程序为服务器提供了两个类,一个是创建ServerSocket监听的主类,一个是负责处理每个Socket通信的线程类.

    package com.net.scday1;
    
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    
    public class MyServer {
    	//定义保存所有Socket的ArrayList
    	public static ArrayList<Socket> scoketList=new ArrayList<Socket>();
    	public static void main(String[] args) {
    		
    		try {
    			ServerSocket ss=new ServerSocket(30000);
    			while (true) {
    				//此代码会阻塞,将一直等待别人的连接
    				Socket s=ss.accept();
    				scoketList.add(s);
    				//每当客户端连接后启动一条ServerThread线程为该客户端服务
    				new Thread(new ServerThread(s)).start();
    			} 
    			
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		
    		
    	}
    
    }
    
    


     

    package com.net.scday1;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.Socket;
    /**
     * 负责处理每个线程通信的线程类
     * @author yulei
     *
     */
    public class ServerThread  implements Runnable{
    	//定义当前线程所处理的Socket
    	Socket s=null;
    	//该线程所处理Socket所对应的输入流
    	BufferedReader br=null;
    	public ServerThread(Socket s) throws IOException{
    		this.s=s;	
    		//初始化该Socket对应的输入流
    		br=new BufferedReader(new InputStreamReader(s.getInputStream()));
    	}
    	public  void run() {
    	try {
    		String content=null;
    		//采用循环不断从Socket中读取客户端发送过来的数据
    		while((content=readFromClient())!=null){
    			//遍历SocketList中的每个Socket
    			//将读到的内容向每个Socket发送一次
    			for(Socket s:MyServer.scoketList){
    				PrintStream ps=new PrintStream(s.getOutputStream());
    				ps.println(content);
    			}
    		}
    		} catch (Exception e) {
    		}
    	}
    	
    	//定义读取客户端数据的方法
    	private String readFromClient(){
    		try {
    			return br.readLine();
    			//如果捕获到异常,表明该Socket对应的客户端已经关闭
    		} catch (IOException e) {
    			//删除该Socket
    			MyServer.scoketList.remove(s);
    		}
    		return null;
    	}
    }
    


    每个客户端应包含两条线程:一条负责读取用户的键盘输入,并将用户的输入数据写入Socket对应的输出流中;一条负责读取Socket对应输入流中的数据(从服务器发送过来的数据),并将这些数据打印输出。其中,负责读取用户键盘输入的线程由MyClinet负责,也就是由程序的主线程负责。客户端程序代码如下:

    package com.net.scday1;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.Socket;
    
    public class MyClient {
    	
    	public static void main(String[] args) throws Exception {
    		Socket s=new Socket("127.0.0.1",30000);
    		//客户端启动ClientThread线程不断读取来自服务器的数据
    		new Thread(new ClientThread(s)).start();
    		//获取该Socket对应的输出流
    		PrintStream ps=new PrintStream(s.getOutputStream());
    		String line=null;
    		//不断读取键盘输入
    		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    		while((line=br.readLine())!=null){
    			if(""==line||"".equals(line.trim())){
    				System.out.println("不允许发送空数据!");
    			}else{
    			//将用户的键盘输入内容写入Socket对应的输出流
    			ps.println(line);
    		}
    	 }
    	}
    }
    

    package com.net.scday1;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.Socket;
    
    public class ClientThread  implements Runnable{
    	//该线程负责处理的Socket
    	private Socket s;
    	//该线程所处理的Socket所对应的输入流
    	BufferedReader br=null;
    	public  ClientThread(Socket s) throws IOException{
    		this.s=s;
    		br=new BufferedReader(new InputStreamReader(s.getInputStream()));
    	}
    	@Override
    	public void run() {
    	try {
    		String content=null;
    		//不断读取Socket输入流中的内容,并将这些内容打印输出
    		while((content=br.readLine())!=null){
    			System.out.println(content);
    		}
    		} catch (Exception e) {
    		}
    	}
    }
    


     

     


     

  • 相关阅读:
    vs快捷键
    深入理解react和redux
    eclispe下maven项目报错解决方式
    ios fixed浮层 光标下移解决方案
    jQuery的extend()用法
    连续数字数值转换成逗号分隔
    css 清除浮动
    恶补JavaScript第二篇
    恶补JavaScript第一篇
    中文英文左右padding一致两端对齐实现(转载)
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300350.html
Copyright © 2011-2022 走看看