还是先上图,现在的年轻人都不喜欢看文字,喜欢浏览图片,那就先把今天刚刚做完的一个东西先发出来,今天做完的“通信弹球”对于现在的我来说“现丑了”
图(a)
图(b)
图a是客户端的一个画板,图b是服务器端的一个画板,绘制在客户端的图像,通过一点点的协议和方法就能传到我们的服务器端,同时显示在服务器端的画板上,仔细看可能发现了(不仔细看也发现了)上面的图和下面的颜色有点不一样,这应该是延迟的原因,就像我们浏览网页时向服务器发送请求,要等半天才会有回应一样,就默认是这样的吧,在原谅的范围以内,图片也看了,下面开始今天的主题------通信。
通信:通信,指人与人或人与自然之间通过某种行为或媒介进行的信息交流与传递,从广义上指需要信息的双方或多方在不违背各自意愿的情况下无论采用何种方法,使用何种媒质,将信息从某方准确安全传送到另方。(此处来自百度)
上了这几节课,我对计算机上的通信的理解也就是:我有东西想给你,但是由于种种原因不能亲自给你,这可能有很多方面的原因,比如说是地域或者是不好意思,所以我要找一个东西来把我想给你的东西寄存在那里(在计算机上也就叫做服务器)如果你也想要知道给你的是什么东西!你就联系上它吧,但是,不是每个人平白无故的就能把我想给你的东西取走,就像寄快递的时候每个寄出的货物都有一个单号一样,服务器也是有号的要连接上他你就要知道他的单号是多少(也就是IP地址,和端口号),连接上后你就可以通过一点点的手段就可以把我的东西取走了。
以上纯属个人见解,如有雷同不甚荣幸!
怎么把东西放到寄存的那个地方呢?他又是怎么送到你的手上的呢?必须要有途径啊,就像快递通过海陆空送到各个地方一样,计算机中的信息也是一样,客户端要传到服务器里面,从服务器再传到客户端也是需要途径的,通信的“管道”,通过管道再加上一些通信的协议,就能实现数据的传输了,如下图所示:
图(c)
黑色的线就模拟了通信的通道,客户机和服务器连接,没个客户机对应着一套传输与接收的方法,进行数据的传输与共享。下面具体交代一下这几天学的东西。说说Java中是怎么实现服务器与客户端的。
在Java中要想编写网络通信,必须要用到java.net包下面的API,首先,我们来创建一个服务器,So easy 几行代码就可以搞定实例如下:
Step1:
//创建一个服务器,并指定一个端口.
ServerSocket server = new ServerSocket(5678);
PS: 端口号是什么?
在网络技术中,端口(Port)大致有两种意思:一是物理意义上的端口,比如,ADSL Modem、集线器、交换机、路由器用 于连接其他网络设备的接口,如RJ-45端口、SC端口等等。二是逻辑意义上的端口,一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。我们这里将要介绍的就是逻辑意义上的端口。
TCP与UDP段结构中端口地址都是16比特,可以有在0---65535范围内的端口号。对于这65536个端口号有以下的使用规定:
/*客户机连接进入后,生成一个Socket对象,需要注意的是。调用了accept()方法
*后,程序就会“阻塞”,就会等在这里,直到有一个客户机连接上来,这个方法才会返回,返回 * 的一个Socket对象就代表了服务器和客户机之间的连接,服务器和客户机上的通信就是在Socket *对象client上进行
/
Socket client = server.accept();
Step3:从Socket连接对象上调用方法得到输入输出流:
OutputStream out = client.getOutputStream();
InputStream ins = client.getInputStream();
Step4:使用输入输出流进行通信数据的读写,从输入流中读取从客户端发来的数据,在输出流写入数据 传送到客户端,这里需要注意的是不同类型的数据传输的机制是不同的入字符串就要先取得字符串的字节。
//连接服务器
Socket socket = new Socket(ip,port);
private DataInputStream dins;
private DataOutputStream dous;
/**
* 连接服务器的方法
* @param ip 客户端的Ip地址
* @param port 服务器的端口号
* @return 成功返回true,失败返回false
*/
public boolean connServer(String ip,int port) {
try {
//连接服务器
Socket socket = new Socket(ip,port);
//得到输入输出流
InputStream ins = socket.getInputStream();
OutputStream ous = socket.getOutputStream();
//读写通信数据
dins = new DataInputStream(ins);
dous = new DataOutputStream(ous);
}catch (Exception e) {
e.printStackTrace();
}
return false;
}
//从服务器上读取数据,以读取整形数据为例
public void readFromServer() {
while(true) {
try {
int x = dins.readInt();
int y = dins.readInt();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//向服务器发送数据以传输整形数据为例:
public void sendXY(int x,int y) {
try {
dous.writeInt(x);
dous.writeInt(y);
} catch (Exception e) {
e.printStackTrace();
}
}
package Tms.netjava.com;
import java.awt.Color;
import java.awt.Graphics;
/**
* 客户端画小球的线程
*
* @author sony
*
*/
public class DrawThread extends Thread {
private Graphics g;
private NetConn nc;
//小球的初始坐标位置
int x=200 ;
int y=300 ;
//设置小球的初试半径,后面碰到四周后,会越来越大,当大到一定程度时也可以缩小(没做)
int rd = 20;
//运动的速度为(1/36)秒每贞,看上去移动的比较平缓
int speed = 1;
int red = 255;
int green = 1;
int blue = 255;
//小球初始角度,是和正上方的夹角的大小
private int angle=30;
// 得到画布的高和宽
public DrawThread(Graphics g) {
this.g = g;
nc = new NetConn();
if (nc.connServer("192.168.56.1", 9090)) {
// 读取数据
nc.start();
}
}
public void run() {
while(true) {
move();
try {
Thread.sleep(1000/36);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 小球运动的方法
*/
public void move() {
//当小球碰到四周时,角度相应的变化,窗体的初始高和宽是(600,400)
if(x<0||x>=600) {
angle = 360 - angle;
//碰到壁后改变小球半径
rd+=10;
}
if(y<0||y>=400) {
angle = 180 - angle;
rd+=10;
}
//测试代码
System.out.println("x==="+x);
System.out.println("y==="+y);
double x11 = speed*Math.sin(angle*Math.PI/180);
double y11 = speed*Math.cos(angle*Math.PI/180);
//因为计算的值为-1到1之间的小数,调用相应的向下floor()取整,和向上ceil取整方法
//并对计算值的正负进行判断,进行相应的处理,纸上画画就明白了。
if(x11<0) {
x += Math.floor(speed*Math.sin(angle*Math.PI/180));
} else{
x += Math.ceil(speed*Math.sin(angle*Math.PI/180));
}
if(y11<0) {
y -=-Math.ceil(-y11);
} else{
y -=Math.ceil(speed*Math.cos(angle*Math.PI/180));
}
//给背景设置变化的颜色,也是清屏的颜色,变换的,好看一点
red-=2;
if(red<=0) {
red=255;
}
green+=5;
if(green>=0) {
green=255;
}
blue-=7;
if(blue<=0) {
blue=255;
}
//将 数据传到服务器端
nc.sendData(x, y,red,green,blue,rd);
g.setColor(new Color(red,green,blue));
g.fillRect(0, 0, 600, 400);
//滚动的小球的颜色也随之改变
g.setColor(new Color(green,blue,red));
g.fillOval(x, y, rd, rd);
}
}
下面贴上服务器端的主要代码:
package tms.netjava.com;
import java.awt.Color;
import java.awt.Graphics;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TmsServer extends Thread {
// 创建画布
private Graphics g;
public TmsServer(Graphics g) {
this.g = g;
}
public void run() {
this.startServer(5678);
}
public void startServer(int port) {
try {
System.out.println("创建服务器在端口:" + port);
// 创建服务器
ServerSocket ss = new ServerSocket(port);
// 等待客户机的链接
Socket client = ss.accept();
// 打印客户机的地址
System.out.println("连接进来一个客户机,客户机的地址为"
+ client.getRemoteSocketAddress());
// 取得输入输出流
InputStream ins = client.getInputStream();
OutputStream ous = client.getOutputStream();
// 读写通信数据
DataInputStream dins = new DataInputStream(ins);
DataOutputStream dous = new DataOutputStream(ous);
// 从客户端得到发来的数据
while (true) {
int x = dins.readInt();
int y = dins.readInt();
int red = dins.readInt();
int green = dins.readInt();
int blue = dins.readInt();
int rd = dins.readInt();
// 清屏
g.setColor(new Color(red, green, blue));
g.fill3DRect(5, 5, 600, 400, false);
// 利用得到坐标将指定的图形画出来
g.setColor(new Color(green, blue, red));
g.fillOval(x, y, rd, rd);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}