C/S框架练习

目标:用java写一个c/s的画图软件

思路

1.client端使用JFrame来设计画面。
2.sever端用socket来进行数据的传输。
3.用MouthListener包来监听鼠标事件。
4.有关过程:在鼠标拖动时将该窗口鼠标坐标传至sever端,然后再由sever端将内容分发至每个client端,从而实现多窗口同步。

代码
client端

Main.java


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.Line2D;
import java.lang.*;
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.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import static java.lang.Integer.parseInt;


public class Main {
     private int x1=0,x2=0,y1=0,y2=0;



     public static void main(String[] args) throws IOException {
          Main mn = new Main();
          mn.Ondraw();
     }


    public void Ondraw()throws UnknownHostException,IOException{
            JFrame fm = new JFrame();
            fm.setTitle("画图");
            fm.setSize(700,700);
            fm.setResizable(false);
            fm.setDefaultCloseOperation(3);
            fm.setLocationRelativeTo(null);
            fm.setVisible(true);
            //上面是程序框架
            Graphics2D g = (Graphics2D)fm.getGraphics();//这个是画笔

            Socket s = new Socket("localhost",8888);//链接的通道
            
            DrawDesigner dd = new DrawDesigner(fm,s);
            fm.getContentPane().setLayout(null);
            
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            
            JPanel panel = new JPanel();
            panel.setBounds(0, 0, 684, 661);
            fm.getContentPane().add(panel);
            panel.setLayout(null);
            //装一个小容器
            //--------------------------------------
            //下面是五个变换按钮
            JButton button = new JButton("");
            button.setBounds(10, 10, 30, 30);
            panel.add(button);
            button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    
                    try {
                        bw.write("black\n");
                        bw.flush();
                    }catch(IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
            button.setBackground(Color.BLACK);
            
            JButton button_1 = new JButton("");
            button_1.setBounds(50, 10, 30, 30);
            panel.add(button_1);
            button_1.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    
                    try {
                        bw.write("red\n");
                        bw.flush();
                    }catch(IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
            button_1.setBackground(Color.RED);
            
            JButton button_2 = new JButton("");
            button_2.setBounds(90, 10, 30, 30);
            panel.add(button_2);
            button_2.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    
                    try {
                        bw.write("blue\n");
                        bw.flush();
                    }catch(IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
            button_2.setBackground(Color.BLUE);
            
            JButton button_3 = new JButton("");
            button_3.setBounds(130, 10, 30, 30);
            panel.add(button_3);
            button_3.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    
                    try {
                        bw.write("green\n");
                        bw.flush();
                    }catch(IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
            button_3.setBackground(Color.GREEN);
            
            JButton btnClearAll = new JButton("Clear all!");
            btnClearAll.setBackground(Color.WHITE);
            panel.add(btnClearAll);
            btnClearAll.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    try {
                        bw.write("clear\n");
                        bw.flush();
                    }catch(IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
            btnClearAll.setBounds(170, 10, 93, 30);
            //----------------------------------------------
            
            
            
            
            dd.setG(g);
            fm.addMouseListener(dd);
            fm.addMouseMotionListener(dd);
            while(true){
                try{
                    BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
                    String mess = br.readLine();
                    System.out.println("sent"+mess);
                    String[] xy = mess.split(",");
                    //从服务器端获得坐标
                    if(xy[0].equals("a")) {//如果是起点坐标
                        System.out.println("1!!");
                        this.x2 = parseInt(xy[1]);
                        this.y2 = parseInt(xy[2]);
                        System.out.println(x2+","+y2);
                    }else if (xy[0].equals("b")){//如果是滑动坐标
                        System.out.println("2!!");
                        this.x1 = parseInt(xy[1]);
                        this.y1 = parseInt(xy[2]);
                        System.out.println(x1+","+y1);
                        if(x1!=0&&x2!=0&&y1!=0&&y2!=0) {
                            System.out.println(x1+","+x2+","+y1+","+y2);
                            g.setStroke(new BasicStroke(1));
                            Line2D line1 = new Line2D.Double(x1, y1, x2, y2);
                            //划线
                            g.draw(line1);
                            x2 = x1;
                            y2 = y1;
                        }
                    }else {//如果点的是五个按钮的话
                        switch(xy[0]) {
                        case "black":g.setColor(Color.BLACK);break;
                        case "red":g.setColor(Color.RED);break;
                        case "blue":g.setColor(Color.BLUE);break;
                        case "green":g.setColor(Color.GREEN);break;
                        case "clear":g.clearRect(0,0,700,700);break;//这里有点小问题。。。
                        //在清除的时候会把按钮也清了,但是鼠标扫过的时候按钮又会出现
                        default:System.out.println("error");break;
                        }
                    }
                    
                }catch(IOException ex){
                    ex.printStackTrace();
                }
            }

        }
}

DrawDesigner.java


import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;

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.OutputStreamWriter;
import java.net.Socket;

import static java.lang.Integer.parseInt;


public class DrawDesigner implements MouseListener, MouseMotionListener, ActionListener {
    private int x1,x2,y1,y2;
    private Graphics2D g;
    private JFrame frame;
    private Socket s;
    private InputStream is;
    private OutputStream os;

    public DrawDesigner(JFrame f,Socket sh) throws IOException {
        this.frame = f;//获取面板
        this.s = sh;//获取传输通道
        this.is = this.s.getInputStream();//输入通道
        this.os = this.s.getOutputStream();//输出通道
    }
    public void setG(Graphics g){//设置画笔
        this.g = (Graphics2D) g;
        this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
    }

    public void actionPerformed(ActionEvent e) {//这个函数用不上,但是必须重载
        System.out.println("动作" + e.getActionCommand());

    }


    public void mouseDragged (MouseEvent e){
        System.out.println("拖动");
        //当拖动的时候应当把拖动的坐标发到服务器端

        try{
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
            bw.write("b"+","+e.getX()+","+e.getY()+"\n");

            bw.flush();

        }catch(IOException ex){
            ex.printStackTrace();
        }
        
    }

    public void mouseMoved (MouseEvent e){

    }

    public void mouseClicked (MouseEvent e){
        System.out.println("单击");

    }

    public void mousePressed (MouseEvent e){
        //当按下时应当把按下的起点坐标传到服务器

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));

        System.out.println("按下");
        //x2 = e.getX();
        //y2 = e.getY();

        try {
            bw.write("a"+","+e.getX()+","+e.getY()+"\n");

            bw.flush();

/*            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String mess = br.readLine();
            System.out.println("��������"+mess);
            String[] xy = mess.split(",");
            x2 = parseInt(xy[1]);
            y2 = parseInt(xy[2]);
*/
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public void mouseReleased (MouseEvent e){
        System.out.println("松开");
        //松开时也要传坐标
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
        try {
            bw.write("a"+","+e.getX()+","+e.getY()+"\n");

            bw.flush();

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public void mouseEntered (MouseEvent e){
        System.out.println("进入");
    }

    public void mouseExited (MouseEvent e){
        System.out.println("脱出");
    }


}

sever端

Sever.java


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;


public class Sever {

    public static String mess;

    public static void main(String[] args)throws IOException{

        List<BufferedWriter> output = new ArrayList<BufferedWriter>();
        ServerSocket se = null;
        Socket s = null;

        try {

            se = new ServerSocket (8888);
            System.out.println ("监听用户连接......");
            while (true) {//客户端的端口正确才能接下去访问,否则要么等待要么报错
                s = se.accept ();//监听,阻塞连接
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                output.add(bw);
                System.out.println ("已监听到客户连接到[远程主机" + s.getRemoteSocketAddress ()
                        + ":端口" +
                        s.getPort () + "]");
                new Thread (new severs (s,output)).start ();
                //每有一个用户连入就多创建一个线程



            }
        } catch (Exception e) {
            e.printStackTrace ();
            System.out.println("服务器断开连接!");
        }


    }
}


class severs implements Runnable{//这个是线程类
    private List<BufferedWriter> op;
    private Socket s = null;
    public severs(Socket s,List<BufferedWriter> opp) {
        this.s = s;
        this.op = opp;
    }


    @Override
    public void run() {
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            //读取客户端发送来的消息
            while((Sever.mess=br.readLine())!=null) {
                System.out.println("客户端:" + Sever.mess);
                for(BufferedWriter bw:op){
                    bw.write(Sever.mess + "\n");
                    bw.flush();
                }
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

总结
该程序有个bug:在清空面板之后会把按钮清除,但是实际上按钮还在。
程序本身不是非常复杂,但是其中的c/s思想值得深讨。
本人拙见,望指教。