百度一下JAVA socket通信 例子 网上一大堆源码

解决方案 »

  1.   

    客户端
    package cn.day05;import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.util.Scanner;
    /**
     * 客户端
     * @author Dwyane_xu
     *
     */
    public class Client {
    //用于与服务器连接的Socket
    private Socket socket;

    public Client(){
    try {
    /**
     * 实例化Socket,用于连接服务器
     * SeverSocket
     * 参数1:服务器的ip地址  localhost表示本机
     * 参数2: 服务端打开的端口
     */
    socket = new Socket("localhost", 8088);


    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    /**
     * 客户端启动方法
     */
    public void start(){
    try {
    /** 启动用于接收服务端发送过来的信息的线程*/

    GetServerInfoHandler  handler = 
    new GetServerInfoHandler();

    Thread t = new Thread(handler);

    t.setDaemon(true);
    t.start();


    /**
     *   V2:
     *    从键盘获取用户输入的一行内容,然后
     *    将其发送给服务器。并且这个操作可以
     *    循环操作 
     */
    //创建Scanner, 用于获取键盘输入放入内容
    Scanner scanner = new Scanner(System.in);



    //java.io.OutputStream
    OutputStream out = socket.getOutputStream();

    OutputStreamWriter osw = 
    new OutputStreamWriter(out,"UTF-8");
    /**
     * 将字节输出流转换为缓冲字符输出流
     */
    PrintWriter writer = 
    new PrintWriter(osw, true);
    while (true) {
    /** 从键盘读取一行内容,发送到服务端去*/
    writer.println(scanner.nextLine());
    }

    /**
     * 创建输入流,用于读取服务器发送过来的信息
     */
    // InputStream in = 
    // socket.getInputStream();
    // InputStreamReader isr = 
    // new InputStreamReader(in);
    // BufferedReader reader = 
    // new BufferedReader(isr);
    //
    // String str = reader.readLine();
    // System.out.println("Server say:"+str);

    } catch (Exception e) {
    e.printStackTrace();
    }
    }


    public static void main(String[] args) {
    //实例化一个客户端
    Client client = new Client();
    //启动客户端
    client.start();
    }

    /**
     * 该线程用于循环读取服务器发送过来的信息
     * 并将其输出到控制台
     * @author Dwyane_xu
     *
     */
    private class GetServerInfoHandler implements Runnable{

    public void run(){

    try {
    InputStream in = socket.getInputStream();
    InputStreamReader isr = 
    new InputStreamReader(in,"UTF-8");
    BufferedReader reader = 
    new BufferedReader(isr);

    /** 循环读取服务端发送的每一行内容*/
    while (true) {
    //读取到后将其输出到客户端的控制台
    String info = reader.readLine();
    if(info == null){
    //若读到空值,就停止该线程
    break;
    }
    System.out.println(info);
    }

    } catch (Exception e) {

    }

    }
    }
    }服务端
    package cn.day05;import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Vector;
    import java.util.concurrent.BlockingDeque;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.LinkedBlockingDeque;/**
     * 服务端
     * @author Dwyane_xu
     *
     */
    public class Server {
    //服务端的ServerSocket
    private ServerSocket server;
    //线程池
    private ExecutorService threadPool;
    //存放所有客户端输出流的集合
    private Vector<PrintWriter> allOut;
    //创建一个消息队列,保存所有带转发的信息
    private BlockingDeque<String> msgQueue;

    public Server(){
    try {
    /**
     * 创建服务端ServerSocket,并指定服务端口
     * 
     */
    System.out.println("Start server.....");

    //初始化消息队列
    msgQueue = new LinkedBlockingDeque<String>();

    //启动消息转发线程
    SendMsgToAllClientHandler sendHandler = 
    new SendMsgToAllClientHandler();

    Thread t = new Thread(sendHandler);
    t.start();

    //初始化存放所有客户端输出流的集合
    allOut = new Vector<PrintWriter>();

    //初始化线程池
    threadPool = Executors.newCachedThreadPool();

    server = new ServerSocket(8088);

    System.out.println("Start server finish....");
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    /**
     * 将一个客户端输出流存入共享集合中
     * @param writer
     */
    /**
     *  synchronized若修饰方法,那么当调用该方法时
     *  锁的对象就是该方法所属的对象,这里就是main方法中
     *  实例化的Server实例
     *  当一个类中的几个方法都被synchronized修饰,那么
     *  这几个方法是同步的 ,并且是互斥的。意思就是
     *  多线程访问方法时,这几个方法选其一,只要有一个线程
     *  执行了其中的一个方法,其他线程对剩下的方法都没有访问权限 
     */
    public synchronized void addClientOut(PrintWriter writer){
    allOut.add(writer);
    }

    /**
     * 将一个客户端的输出流从共享集合中删除
     * @param writer
     */
    public synchronized void removeClientOut(PrintWriter writer){
    allOut.remove(writer);
    }

    /**
     * 将给定的信息转发给所有客户端
     * @param msg
     */
    public synchronized void sendMsgToAllClient(String msg){
    /** 遍历所有客户端输出流*/
    for(PrintWriter writer : allOut){
    /** 将给定的字符串发给每一个客户端*/
    writer.println(msg);
    }

    }

    /**
     * 服务端启动方法
     */
    public void start(){
    try {
    //System.out.println("Wait client connect....");

    /**
     * Socket accept()
     * 该方法是一个阻塞方法,直到一个客户端Socket
     * 连接,该方法才会返回,而返回的结果
     * 就是这个客户端的Socket
     */

    /**
     * V3
     *   若想让服务端可以同时连接上不同客户端
     *   那么我们就需要重复的调用accept()方法
     *   这样服务端才能发现其他客户端的连接
     *   但这里要是使用循环来监听客户端的连接,带来
     *   的问题就是不能与连接上的客户端交互了。所以
     *   需要启动线程来处理与连接上的客户端交互
     */

    while(true){
    System.out.println("Wait client connect....");
    Socket socket = server.accept();
    System.out.println("A client connected!");

    String hostName = socket.getInetAddress().getHostName();

    String address = socket.getInetAddress().getHostAddress();

    System.out.println("HostName:"+hostName);
    System.out.println("HostAddress:"+address);

    /** 创建线程,用于监听当前连接的客户端发送的信息*/

    GetClientInfoHandler handler = 
    new GetClientInfoHandler(socket);

    // Thread t = new Thread(handler);
    // t.start();

    /**
     * 将任务指派给线程池,使其分配线程来
     * 运行任务
     */
    threadPool.execute(handler);

    }




    /**
     * 服务端创建输出流,用于向客户端发信息
     */
    // OutputStream out = 
    // socket.getOutputStream();
    // PrintWriter writer = 
    // new PrintWriter(out);
    // writer.println("Hello Client");
    // writer.flush();

    } catch (Exception e) {

    }

    }

    public static void main(String[] args) {
    //实例化服务端对象
    Server server = new Server();
    //启动服务端
    server.start();
    }

    /**
     * 这个线程体用来在线程中
     * 并发执行,与一个给定的客户端交互
     * @author Dwyane_xu
     *
     */
    private class GetClientInfoHandler implements Runnable{ //用来交互的客户端Socket
    private Socket socket;

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

    public void run() {
    //当前客户端输出流
    PrintWriter writer = null;

    /**
     * 在线程中,获取该客户端的输入流,用于
     * 读取客户端发送过来的数据
     */
    try {
    //java.io.InputStream
    InputStream in = socket.getInputStream();

    InputStreamReader isr = 
    new InputStreamReader(in,"UTF-8");

    BufferedReader reader = 
    new BufferedReader(isr);

    /**
     * 创建用于向客户端发送信息的输出流
     * 并存入共享集合
     */

    OutputStreamWriter osw = 
    new OutputStreamWriter(socket.getOutputStream(),"UTF-8");

    writer = new PrintWriter(osw, true);
    addClientOut(writer);

    /**
     * V2
     *  循环读取客户端发送过来的每一条数据
     *  并输出到控制台
     */
    while(true){
    /**
     * 读取客户端发送过来的一行字符串
     */
    String info = reader.readLine();
    if(info == null){
    throw new RuntimeException("Client connect exception");
    }
    //     System.out.println("Client say:"+ info);
    /**
     * 每当读取到该客户发送过来的信息
     * 就转发个所有客户端
     * 
     * 这样存在缺陷。多线程同时转发可能会产生数据混乱的现象
     * 
     * 正确的做法是,将转发的数据存入消息队列,等待同一转发
     */
    // sendMsgToAllClient(info);
    //向消息队列中添加一个信息
    msgQueue.offer(info);

    }


    } catch (Exception e) {
    e.printStackTrace();
    } finally{
    try {
    //在和该客户端断开连接前,应该将该客户端的输出流从共享集合中删除
    if(writer != null){
    removeClientOut(writer);
    }

    //若和客户端连接存在异常,就关闭这个客户端连接
    socket.close();

    } catch (Exception e2) {
    e2.printStackTrace();


    }
    }
    }

    }

    /**
     * 该线程用于周期性的从消息队列中读取信息
     * 并转发给所有的客户端
     * @author Dwyane_xu
     *
     */

    private class SendMsgToAllClientHandler implements Runnable{

    public void run(){
    /** 遍历消息队列,将消息转发*/
    while(true){
    //从消息队列中取出第一条消息
    String msg = msgQueue.poll();
    if(msg != null){
    //若有消息就转发
    sendMsgToAllClient(msg);
    } else {
    //若没有消息,则休息
    try {
    Thread.sleep(30);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }

    }
    }
    }
      

  2.   

    Socket -> RMI -> J2EE