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();
}
}
}
}
Java
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(" 脱出 ");
}
}
Java
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();
}
}
}
Java
总结
该程序有个 bug: 在清空面板之后会把按钮清除,但是实际上按钮还在。
程序本身不是非常复杂,但是其中的 c/s 思想值得深讨。
本人拙见,望指教。