java的C/S框架练习
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思想值得深讨。
本人拙见,望指教。