通信,指人与人或人与自然之间通过某种行为或媒介进行的信息交流与传递,从广义上指需要信息的双方或多方在不违背各自意愿的情况下无论采用何种方法,使用何种媒质,将信息从某方准确安全传送到另方。[百科释义]
个人认为通信就是通过特定规格(所谓的协议)传输和读取信息。就像男女之间的交往,可以通过不同途径认识的一样,这种协议并不是每家公司或者每个人都是一样的,如果一样,接触过协议的人就可以轻松破解传输的信息并读取,于是就有了通信安全。所以通信的主要内容就是文件的传输和读写,而文件的传输的读写只要就依靠协议的制定,就通信部分而言,刚接触到协议,对通信有了简单的认识
简单叙述下创建服务器和客户端的过程
服务器创建:
第一步:在指定端口上创建一个java.net.ServerSocket对象,如下代码:
ServerSocket server=new ServerSocket(8023);
System.out.println("服务器创建成功!"+port);
第二步:当服务器创建成功后,让服务器进入等待状态,等待其它的客户机来连结:
//在等待客户机连结进入,进入后,生成一个Socket对象
java.net.Socket client=server.accept();
System.out.println("Incoming "+client.getRemoteSocketAddress());
第三步:从Socket连结对象上调用方法得到输入输出流:
java.net.Socket client=server.accept();
//从连结对象上得到输入/输出流对象
OutputStream out=client.getOutputStream();
InputStream ins=client.getInputStream();
客户端创建
Socket client=new Socket(“服务器IP”,服务器端口);
在谈谈对编写这个网络画板过程吧,最初的想法是做成一个聊天登录界面,可以发送消息,然后输入框为空的时候点击“Send”按钮是就会弹出一个窗体,客户端此时也会弹出与服务器属性相同的窗体,然后就可以在窗体上绘图,然后客户端显示的图形与服务器画的一样。
expectation:
但是,理想很丰满,现实很骨感...于是在各个文件传参的时候出现的如下的情况...
于是就从各个文件中找各个参数,逐一地测试,输出,特别是从监听器中传参出来,简直就是一个恶魔在心头萦绕。有几个参数传到目的文件要经过几个文件,这也难怪会出现上述问题,这么多文件总有那么几个文件会出问题...
最后,采取了一个比较折中的方式,就是暂时取消了发送消息的功能和登录验证的功能,以后有必要再加上去,添加了菜单栏,并将绘图命令集成在菜单项中。
再感悟:经过这次简单网络画板的设计,我感到自己在模块整合方面还有待提高,自己写的代码与“搞内聚,低耦合”的理念有一定的距离,但我相信这将会是一个好的开始,并将激励我们发展优秀的设计思路,合理的软件布局。我也相信经过时间的洗礼,骨感的现实终将丰满起来、、、
简单网络画板代码
package com.netBord20130729;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
/**
* 简单网络画板服务器端
* 界面+通信
* 继承自Thread线程类,实现MouseListener接口
* @author YangKang
*
*/
public class NetDrawBordServer extends Thread implements MouseListener{
//定义属性,用来存储按下和释放的坐标值
private int x1;
private int y1;
private int x2;
private int y2;
private int port = 8023; //服务器端口号
private ServerSocket server; //服务器
private Graphics g; //画布对象
private OutputStream ous; //输出流对象
private InputStream ins; //输入流对象
private DataOutputStream dous; //数据输出流
private DataInputStream dins; //数据输入流
private Socket client; //客户端
private byte type; //绘制图形的类型
private String drawCmd = "null"; //菜单命令
//定义入口主函数
public static void main(String args[]) {
NetDrawBordServer ndbs = new NetDrawBordServer();
ndbs.GUI();
ndbs.Conn2Client();
}
/**
* 创建一个窗体,作为服务器端的画板
*/
private void GUI() {
JFrame netBord = new JFrame();
netBord.setTitle("网络画板服务器端");
netBord.setSize(new Dimension(600,500));
netBord.setDefaultCloseOperation(0);//设置默认关闭操作为不执行任何操作
netBord.setLocationRelativeTo(null);
netBord.setLayout(new FlowLayout(FlowLayout.LEFT));//设置窗体布局方式为流式布局
//添加窗体左上角及最小化的图标
ImageIcon frame_icon =new ImageIcon("netPic/0.jpg");
netBord.setIconImage(frame_icon.getImage());
//添加一个退出确认弹出框,前面定义关闭方式为0
netBord.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
if(JOptionPane.showConfirmDialog(null,"是否退出")==JOptionPane.OK_OPTION){
System.exit(0);
}
}
});
//创建菜单条
JMenuBar menuBar = new JMenuBar();
//创建菜单
JMenu menuF = new JMenu("文件(F)");
//添加菜单项
JMenuItem newItem = new JMenuItem("新建(N)");
JMenuItem openItem = new JMenuItem("打开(O)");
JMenuItem saveItem = new JMenuItem("保存(S)");
//实例化一个水平分隔符对象
JSeparator jse = new JSeparator();
JMenuItem exitItem = new JMenuItem("退出(E)");
//将菜单添加到窗体中
netBord.add(menuBar);
//菜单添加到菜单条
menuBar.add(menuF);
//将菜单项添加到菜单
menuF.add(newItem);
menuF.add(openItem);
menuF.add(saveItem);
menuF.add(jse);
menuF.add(exitItem);
JMenu menuE = new JMenu("编辑(E)");
JMenuItem drawLine = new JMenuItem("画直线(L)");
JMenuItem drawOval = new JMenuItem("画椭圆(O)");
JMenuItem drawRect = new JMenuItem("画矩形(R)");
JMenuItem drawTri = new JMenuItem("画三角形(T)");
menuBar.add(menuE);
menuE.add(drawLine);
menuE.add(drawOval);
menuE.add(drawRect);
menuE.add(drawTri);
JMenu menuH = new JMenu("帮助(H)");
JMenuItem aboutItem = new JMenuItem("关于(A)");
menuBar.add(menuH);
menuH.add(aboutItem);
//给菜单项添加动作监听器,menuListener为内部监听器
openItem.addActionListener(menuListener);
saveItem.addActionListener(menuListener);
exitItem.addActionListener(menuListener);
drawLine.addActionListener(menuListener);
drawOval.addActionListener(menuListener);
drawRect.addActionListener(menuListener);
drawTri.addActionListener(menuListener);
aboutItem.addActionListener(menuListener);
//最后加上set语句可以将菜单栏添加到窗体顶部
netBord.setJMenuBar(menuBar);
netBord.setVisible(true);
//在窗体可见之后,获取画布的对象
g = netBord.getGraphics();
//给窗体添加鼠标监听器
netBord.addMouseListener(this);
}
/**
* 菜单栏内部监听器,用于将采集所有菜单栏的命令
*/
ActionListener menuListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if("画直线(L)".equals(cmd)){
drawCmd = "line";
System.out.println("画直线的监听器启动:"+drawCmd);
}else if("画椭圆(O)".equals(cmd)){
drawCmd = "oval";
System.out.println("画椭圆的监听器启动:"+drawCmd);
}else if("画矩形(R)".equals(cmd)){
drawCmd = "rectangle";
System.out.println("画矩形的监听器启动:"+drawCmd);
}else if("画三角形(T)".equals(cmd)){
drawCmd = "triangle";
System.out.println("画三角形的监听器启动:"+drawCmd);
}
/******************************************新建文件*****************************/
else if("新建(N)".equals(cmd)){
//本地功能已经实现,网络功能待完善,在此不展示
}
/******************************************保存文件*****************************/
else if("保存(S)".equals(cmd)){
//本地功能已经实现,网络功能待完善,在此不展示
}
/******************************************打开文件*****************************/
else if("打开(O)".equals(cmd)){
//本地功能已经实现,网络功能待完善,在此不展示
}
/******************************************退出操作*****************************/
else if("退出(E)".equals(cmd)){
System.out.println("退出的监听器启动");
System.out.println("程序已经关闭");
System.exit(0);
}
/******************************************关于信息*****************************/
else if("关于(A)".equals(cmd)){
System.out.println("关于的监听器启动");
JFrame aboutFrame = new JFrame("关于\"画板\"");
aboutFrame.setSize(280,240);
aboutFrame.setDefaultCloseOperation(2);
aboutFrame.setResizable(false);
aboutFrame.setLocationRelativeTo(null);
aboutFrame.setLayout(new FlowLayout());
aboutFrame.setVisible(true);
JLabel label = new JLabel();
//创建一个超链接
final JLabel la_url = new JLabel("博客:http://yacare.iteye.com");
//设置链接颜色为蓝色
la_url.setForeground(Color.BLUE);
label.setText("<html><body>Certified by Internet Society<br>"
+ "网络画板服务器端 (本大爷专属)<br>@author YangKang<br>@version 1.0<br>"
+ "©Copyright 版权所有,山寨必究<br>本软件只供学习娱乐之用,严禁从事商业用途"
+ "<br><br>联系作者:<br>"
+ "QQ:1009425612<br>TEL:18942558998<br>"
+ "Addess:保密"
+ "</body></html>");
aboutFrame.add(label);
aboutFrame.add(la_url);
//将链接添加鼠标监听器
la_url.addMouseListener(new MouseAdapter() {
//鼠标离开时,链接前景色变为橙色
@Override
public void mouseExited(MouseEvent e) {
la_url.setForeground(Color.ORANGE);
}
//鼠标进入时,链接前景色变成红色
@Override
public void mouseEntered(MouseEvent e) {
la_url.setForeground(Color.RED);
}
//鼠标点击超链接时,打开浏览器进入链接地址
@Override
public void mouseClicked(MouseEvent e) {
try {
//定义链接地址
URI uri = new URI("http://yacare.iteye.com");
Desktop dtp = Desktop.getDesktop();
//是否支持此类和对象浏览
if(Desktop.isDesktopSupported()&&dtp.isSupported(Desktop.Action.BROWSE)){
//在浏览器中打开此链接
dtp.browse(uri);
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
}
}
};
/**
* 网络画板通信模块,连接客户端
*/
private void Conn2Client() {
try{
//1.建立绑定在指定端口上的服务器对象
server = new ServerSocket(port);
System.out.println("服务器创建成功"+this.port);
//2.当有客户机连接时,等待方法就会返回,返回一个代表与客户端连接的对象
while(true){
//让服务器处于循环待机状态
client = server.accept();//可能会发生堵塞
//创建客户端的输出流
ous = client.getOutputStream();
dous = new DataOutputStream(ous);
//创建客户端的输入流
ins = client.getInputStream();
dins = new DataInputStream(ins);
System.out.println("Incoming"+client.getRemoteSocketAddress().toString());
//启动读取客户端数据的线程
this.start();
System.out.println("处理线程已启动,正处理登录操作!");
}
}catch(Exception e1){
e1.printStackTrace();
}
}
/**
* 重写父类run()方法,用来读取客户端的数据
*/
public void run(){
//在线程run中调用处理连结的方法
readLineFromClient(dins);
}
/**
* 将发送图形的代码封装到sendLine2Client方法中
* @param type 图形的类型
* @param 传入两点的坐标
*/
public void sendLine2Client(int type,int x1,int y1,int x2,int y2){
try {
dous.writeByte(type); //type 表示绘制图形类型
dous.writeInt(x1);
dous.writeInt(y1);
dous.writeInt(x2);
dous.writeInt(y2);
ous.flush(); //强制输出
System.out.println("向服务器发送直线成功");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 读取客户端发过来的直线信息,接收并画在窗体上
*/
private void readLineFromClient(DataInputStream dins) {
try {
while(true){
type = dins.readByte();
x1 = dins.readInt();
y1 = dins.readInt();
x2 = dins.readInt();
y2 = dins.readInt();
System.out.println("读取客户端发送来的图形数据成功,类型:"+type);
//判断绘制图形的类型
if(type == 1){ //1表示画直线
//根据传入的坐标,调用绘制直线的方法来画直线
g.drawLine(x1,y1,x2,y2);
}else if(type == 2){//2表示画椭圆
//根据传入的坐标,调用绘制椭圆的方法来画椭圆
int minX = Math.min(x1, x2);
int minY = Math.min(y1, y2);
g.drawOval(minX,minY,Math.abs(x2-x1),Math.abs(y2-y1));
}else if(type == 3){//3表示画矩形
//根据传入的坐标,调用绘制矩形的方法来画矩形
int minX = Math.min(x1, x2);
int minY = Math.min(y1, y2);
g.drawRect(minX,minY,Math.abs(x2-x1),Math.abs(y2-y1));
}else if(type == 4){//4表示画三角形
//根据传入的坐标,调用绘制直线的方法来画等腰三角形
g.drawLine(x1,y1,x2,y2);
g.drawLine(x1,y1,x1*2-x2,y2);
g.drawLine(x2,y2,x1*2-x2,y2);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
dins.close();
ins.close();
ous.close();
dous.close();
client.close();
}catch (Exception e2) {
e2.printStackTrace();
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println("鼠标监听器得到命令:"+drawCmd);
//获取鼠标按下时的坐标值
x1 = e.getX();
y1 = e.getY();
System.out.println("鼠标按下的坐标:"+"x1-->"+x1+",y1-->"+y1);
}
@Override
public void mouseReleased(MouseEvent e) {
//获取鼠标释放时的坐标值
x2 = e.getX();
y2 = e.getY();
System.out.println("鼠标松开的坐标:"+"x2-->"+x2+",y2-->"+y2);
System.out.println("鼠标捕捉到的点坐标:x1-->"+x1+" y1-->"+y1+" x2-->"+x2+" y2-->"+y2);
//根据命令,获取按下和释放的坐标,调用绘制直线的方法来画线/画圆
if(drawCmd.equals("null")){
JOptionPane.showMessageDialog(null, "请先选择绘图命令");
System.out.println("未指定画图命令,请选择画图类型");
System.out.println("**************************************");
}if(drawCmd.equals("line")){
//根据按下和释放的坐标,调用绘制直线的方法来画直线
g.drawLine(x1,y1,x2,y2);
//将绘图数据传到客户端
type = 1; //1表示绘制图形为直线
sendLine2Client(type,x1,y1,x2,y2);
System.out.println("画直线成功");
System.out.println("**************************************");
}if(drawCmd.equals("oval")){
//根据按下和释放的坐标,调用绘制椭圆的方法来画椭圆
int minX = Math.min(x1, x2);
int minY = Math.min(y1, y2);
g.drawOval(minX,minY,Math.abs(x2-x1),Math.abs(y2-y1));
//将绘图数据传到客户端
type = 2; //2表示绘制图形为椭圆
sendLine2Client(type,x1,y1,x2,y2);
System.out.println("画椭圆成功");
System.out.println("**************************************");
}if(drawCmd.equals("rectangle")){
//根据按下和释放的坐标,调用绘制直线的方法来画矩形
g.drawLine(x1,y1,x2,y1);
g.drawLine(x1,y1,x1,y2);
g.drawLine(x1,y2,x2,y2);
g.drawLine(x2,y1,x2,y2);
//将绘图数据传到客户端
type = 3; //3表示绘制图形为矩形
sendLine2Client(type,x1,y1,x2,y2);
System.out.println("画矩形成功");
System.out.println("**************************************");
}if(drawCmd.equals("triangle")){
//根据按下和释放的坐标,调用绘制直线的方法来画等腰三角形
g.drawLine(x1,y1,x2,y2);
g.drawLine(x1,y1,x1*2-x2,y2);
g.drawLine(x2,y2,x1*2-x2,y2);
//将绘图数据传到客户端
type = 4; //3表示绘制图形为等腰三角形
sendLine2Client(type,x1,y1,x2,y2);
System.out.println("画三角形成功");
System.out.println("**************************************");
}
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}