这几天一直在做通信这方面的东西,刚开始的时候真的觉得不能很好的理解,但是同时也觉得
真的很神奇。现在就讲解一下我再这方面学到的东西,以及在学习的过程中所遇到的问题。
话不多说,先传上我的成果。

可能你刚开始的时候也会觉得这里有的东西是无法理解的。让我一步一步解释。
首先这是一个通信的问题,我记得有个人说过计算机因为有了通信而变得很不一样了,当时刚
听这句话是,没有明白到底是神马意思,学过通信过后才深刻的领悟了这句话。话不多说,开
启我们的通信之旅。
首先通信是有服务器和客户端构成的,也就是我们必须要通过服务器来实现链接,在java中有
这样的一个类 ServerSocket ;我们可以通过这个类创建一个服务器对象代码如下:
ServerSocket serverSocket = new ServerSocket(9090);
9090是我们创建的服务器的端口号,这个端口号是有1-60000多的数字,我们要竟可能挑选大
一点的数字,因为小的数字可能已经被系统占用,这样我们创建了一个服务器了,那么怎么与
客户端链接呢,看下面代码:
Socket socket = serverSocket.accept()
这句代码的意思是我们的服务器在等待客户端
来连接,如果没有链接那么整个程序就一直阻塞在这里,换句话说我们必须有客户端链接程序
才能继续运行,试想如果没有客户端链接,服务器还用运行吗,当我们获得socke对象后我们
就必须要获取服务器的输入输出流;看下面代码:
InputStream ins = socket.getInputStream();
OutputStream out = socket.getOutputStream();
那么我们为什么要获取输入流输出流呢?这是因为我们整个通信就是读写数据,我们要获取从
客户端输入的数据然后再进写给其他的客户端,同时我们客户端也要实现一些公告什么的功能
,我可以说整个服务器就是上面的四行代码。服务器就先到这了,我们接下来要说一下客户端
,同样客户端也是几行代码.首先我们要创建一个客户端,这个客户端要链接上服务器,看下
面的代码:
Socket socket = new Socket("localhost",9090);
这行代码是创建一个客户端,构造方法的第一个参数是服务器的ip地址,第二个参数是服务器
的端口号,这样就创建了一个客户端了 同样我们也要获取客户端的输入输出流;代码如下:
InputStream ins = socket.getInputStream();
OutputStream out = socket.getOutputStream();
这样我们应该大体上对客户端和服务器有了一定的了解了,让我举个形象化的列子吧。两桶水
在这两桶水中间有跟管道,当客户端与服务器连接上了,就打开管道阀门了,这时就可以传递
了,服务器那边写客户端就读,客户端写服务器就读。就此我也讲一下群聊的实现吧,就是我
客户端写给服务器读,当服务器读到了就发给每个链接上的客户端,这样就实现了群聊的功能
,你是不是也觉得挺简单的。
接下来我们通过一个群聊和同步画图实例来讲解。
先看上图:

接下来让我们来好好分析一下这个小项目,同时也将一下我在这个项目中遇到的问题。
首先看一下我们的项目的UML分析图:
先看我们的服务器的:

在看我们的客户端的:

现在我们再来说一下这个到底是怎么实现的,首先我们的服务器是创建成功了,但是我们在上面已经说过了
Socket socket = serverSocket.accept()
服务器是一直在等待客户端来连接,那么整个程序就不再向下运行了,这时候我们考虑到使用线程,这样我们就能很好的解决这个问题,因为线程是并发同时运行的。当我们解决好这个问题后,我们要考虑服务器的读取数据,在这个问题中跟客户端是一样的,因为我们客户端和服务器是一直在读取数据,那么也就是说
我们用一个死循环来调用读取的方法,代码如下:
public void process(){
try {
ins = this.socket.getInputStream();
out = this.socket.getOutputStream();
dins = new DataInputStream(ins);
dout = new DataOutputStream(out);
while (true) {
byte b = dins.readByte();
if(b==1){
int x1 = dins.readInt();
int y1 = dins.readInt();
int x2= dins.readInt();
int y2 = dins.readInt();
transDate( b, x1, y1, x2, y2);
g.drawLine(x1, y1, x2, y2);
}else if(b==2){
int x1 = dins.readInt();
int y1 = dins.readInt();
int x2= dins.readInt();
int y2 = dins.readInt();
transDate( b, x1, y1, x2, y2);
g.drawOval(x1, y1, x2-x1, y2-y1);
}else if(b==3){
sendMsg();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//创建一个传输数据的方法
public void transDate(byte b,int x1,int y1,int x2,int y2){
int t = SeverThreadList.SeverList.size();
for(int i=0;i<t;i++){
try {
SeverThreadList.SeverList.get(i).dout.writeByte(b);
SeverThreadList.SeverList.get(i).dout.writeInt(x1);
SeverThreadList.SeverList.get(i).dout.writeInt(y1);
SeverThreadList.SeverList.get(i).dout.writeInt(x2);
SeverThreadList.SeverList.get(i).dout.writeInt(y2);
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面我们用一个while的死循环,但是这时问题又来了,整个程序又卡在这里了,解决方法如上,也是放在一个线程里,这样就可以了;同样客户端也是这样处理的,就是我们将一个客户端的读取数据也放在线程里。
,接下来我们来说一下群聊的实现:
Socket socket = serverSocket.accept()
这是我们获取的socket,我要解释一下,这可socket是不一样的,也就是处理每个客户端的socket是不一样的,那么我们可以将它放入链表中,这样当服务器接受到客户端发来的信息,我们在遍历这个链表将信息发出去,这样我们就实现了群聊了,看下面代码:
public void createServer(){
try {
ServerSocket serverSocket = new ServerSocket(9090);
System.out.println("服务器创建成功");
while (true) {
Socket socket = serverSocket.accept();
System.out.println("有客户端连接了");
IoThread ioThread = new IoThread(socket,this.g,area);
SeverThreadList.SeverList.add(ioThread);
ioThread.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//创建一个传输数据的方法
public void transDate(byte b,int x1,int y1,int x2,int y2){
int t = SeverThreadList.SeverList.size();
for(int i=0;i<t;i++){
try {
SeverThreadList.SeverList.get(i).dout.writeByte(b);
SeverThreadList.SeverList.get(i).dout.writeInt(x1);
SeverThreadList.SeverList.get(i).dout.writeInt(y1);
SeverThreadList.SeverList.get(i).dout.writeInt(x2);
SeverThreadList.SeverList.get(i).dout.writeInt(y2);
} catch (IOException e) {
e.printStackTrace();
}
}
}
这样我们就实现了群聊的功能了,接下来我再说一下我在写通信是所遇到的问题,有的注意点已经在上面讲过了,就不再赘述了。在实现通信时,要先注意你的通信协议,这个是通信的灵魂,比如我上面的项目就是我换线的时候我先写一个byte为1然后在写数据,我花圆的时候先写一个byte为2然后在写数据,这样当我接收到数据时就先读取这个byte数据,如果为1那么我就读取画线的数据,如果为2那么我就读取画圆的数据,
第2 要注意读取数据的细节之处,看下面的代码:
c = (char)dins.read();
while(c!='#'){
message +=c;
c = (char)dins.read();
}
message = new String(message.getBytes("ISO-8859-1"),"GB2312");
我们必须有一个读取结束的标志,在标志前的数据我们要保存。
这样我们就对通信有了一定的了解,后面就得靠自己来实际动手来做,我报上面的项目的代码放在附件中,如有问题,请给我留言。




