Java中利用socket实现简单的服务端与客户端的通信(中级)——实现任意双向通信

本文计划采用socket实现客户端和服务端的任意双向通信,即客户端可以随时给服务端发消息,服务端也可以随时给客户端发消息,最终结果就是一个类似与QQ的聊天软件的功能。

以下代码可以直接拷贝到Eclipse中运行。

前面的两片文章都利用了socket实现了客户端与服务器的通信,我的前两片文章:

Java中利用socket实现简单的服务端与客户端的通信(入门级),实现了一个简单的客户端发送消息,服务器端接收消息的实力,没有多线程,也没有让服务器端有消息返回。 

Java中利用socket实现简单的服务端与客户端的通信(基础级),在上一篇的基础上,在服务端实现了多线程,使得服务端可以于多个客户端连接并接收他们发送的消息。


要想实现任意的双向通信,以客户端来说,时刻既需要能够发送消息,同时也需要能够随时的接收服务端发来的消息,这两个功能必须同时存在,还必须同时运行,所以这个时候就必须使用到多线程了。无论是服务端还是客户端,都至少需要多出两个线程,一个线程用于发送数据,一个线程用于接收数据。这是本文的关键。

客户端:

package client_3;

import java.io.BufferedReader;  
import java.io.DataInputStream;  
import java.io.DataOutputStream;  
import java.io.IOException;  
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;  
  
public class client_3 {  
  
    public static final String IP = "localhost";//服务器地址   
    public static final int PORT = 10000;//服务器端口号    
  
    public static void main(String[] args) {
    	
        handler();   
    }  
  
    private static void handler(){  
        try {    	
            //实例化一个Socket,并指定服务器地址和端口  
            Socket client = new Socket(IP, PORT);  
            System.out.println("I am a client");    
            //开启两个线程,一个负责读,一个负责写  
            new Thread(new ReadHandlerThread(client)).start();  
            new Thread(new WriteHandlerThread(client)).start();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}    
  
/*  
 *处理读操作的线程   
 */  
class ReadHandlerThread implements Runnable{  
    private Socket client;  
  
    public ReadHandlerThread(Socket client) {  
        this.client = client;  
    }  
    @Override  
    public void run() {  
    	BufferedReader in = null;
    	try {
			in = new BufferedReader(new InputStreamReader(client.getInputStream()));
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
        try {  
            while(true){ 
            	System.out.println("服务器说:"+in.readLine());    
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally{              
                if(client != null){  
                    client = null;  
                }  
        }  
    }  
}  
  
/*  
 * 处理写操作的线程  
 */  
class WriteHandlerThread implements Runnable{  
    private Socket client;  
  
    public WriteHandlerThread(Socket client) {  
        this.client = client;  
    }  
  
    @Override  
    public void run() {  
    	PrintWriter out=null;
		try {
			out = new PrintWriter(client.getOutputStream());
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}                 
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));//从控制台获取输入的内容  
        try {  
            while(true){  
            	out.println(reader.readLine());  
            	out.flush();
             }  
        } catch (IOException e) {  
            e.printStackTrace();     
        }
        try {
			client.close();
			 reader.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        out.close();
       
        
    }  
}  
可以看到,上述代码有两个线程类,一个负责读,一个负责写,同样的,服务端的代码也大同小异。


服务端:

package server_3;

import java.io.BufferedReader;  
import java.io.DataInputStream;  
import java.io.DataOutputStream;  
import java.io.IOException;  
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;  
import java.net.Socket;  
  
public class server_3 {  
  
    public static final int PORT = 10000;//监听的端口号     
  
    public static void main(String[] args) {    
    	System.out.println("sever begins");
    	server_3 server = new server_3();    
        server.init();    
    }    
  
    public void init() {    
        ServerSocket serverSocket = null;  
        try {    
            serverSocket = new ServerSocket(PORT);    
            while (true) {    
                Socket client = serverSocket.accept();    
                //一个客户端连接就开两个线程分别处理读和写    
                new Thread(new ReadHandlerThread(client)).start();    
                new Thread(new WriteHandlerThread(client)).start();   
            }    
        } catch (Exception e) {    
            e.printStackTrace();    
        } finally{  
            try {  
                if(serverSocket != null){  
                    serverSocket.close();  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }    
}    
  
/*  
 *处理读操作的线程   
 */  
class ReadHandlerThread implements Runnable{  
    private Socket client=null;  
    
    public ReadHandlerThread(Socket client) {  
        this.client = client;  
    }  
  
    @Override  
    public void run() {  
    	BufferedReader in = null;
        try{  
            while(true){  
                //读取客户端数据    
            	in = new BufferedReader(new InputStreamReader(client.getInputStream()));
                System.out.println("客户端说:" + in.readLine());   
            }  
        }catch(Exception e){  
            e.printStackTrace();  
        }finally{  
            if(client != null){  
			    client = null;  
			}  
        }  
    }  
}  
  
/*  
 * 处理写操作的线程  
 */  
class WriteHandlerThread implements Runnable{  
    private Socket client;  
  
    public WriteHandlerThread(Socket client) {  
        this.client = client;  
    }  
  
    @Override  
    public void run() {  
        PrintWriter out=null;
		try {
			out = new PrintWriter(client.getOutputStream());
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}  
    	BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));//从控制台获取输入的内容 
        try{  
            while(true){  
                //向客户端回复信息    
            	out.println(reader.readLine());
            	out.flush();  
            }  
        }catch(Exception e){  
            e.printStackTrace();  
        }finally{  
            if(client != null){  
			    client = null;  
			}  
        }  
    }  
}  

以上程序,先启动服务端,再启动客户端,就可以实现两端的任意聊天,功能和qq等软件类似。



2015年11月26日   西安交通大学



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值