基于Java回顾之网络通信的应用分析

TCP连接

TCP的基础是Socket,在TCP连接中,我们会使用ServerSocket和Socket,当客户端和服务器建立连接以后,剩下的基本就是对I/O的控制了。

我们先来看一个简单的TCP通信,它分为客户端和服务器端。

客户端代码如下:


代码如下:

简单的TCP客户端
 import java.net.*;
 import java.io.*;
 public class SimpleTcpClient {

public static void main(String[] args) throws IOException
     {
         Socket socket = null;
         BufferedReader br = null;
         PrintWriter pw = null;
         BufferedReader brTemp = null;
         try
         {
             socket = new Socket(InetAddress.getLocalHost(), 5678);
             br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             pw = new PrintWriter(socket.getOutputStream());
             brTemp = new BufferedReader(new InputStreamReader(System.in));
             while(true)
             {
                 String line = brTemp.readLine();
                 pw.println(line);
                 pw.flush();
                 if (line.equals("end")) break;
                 System.out.println(br.readLine());
             }
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
         finally
         {
             if (socket != null) socket.close();
             if (br != null) br.close();
             if (brTemp != null) brTemp.close();
             if (pw != null) pw.close();
         }
     }
 }

服务器端代码如下:


代码如下:

简单版本TCP服务器端
 import java.net.*;
 import java.io.*;
 public class SimpleTcpServer {

public static void main(String[] args) throws IOException
     {
         ServerSocket server = null;
         Socket client = null;
         BufferedReader br = null;
         PrintWriter pw = null;
         try
         {
             server = new ServerSocket(5678);
             client = server.accept();
             br = new BufferedReader(new InputStreamReader(client.getInputStream()));
             pw = new PrintWriter(client.getOutputStream());
             while(true)
             {
                 String line = br.readLine();
                 pw.println("Response:" + line);
                 pw.flush();
                 if (line.equals("end")) break;
             }
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
         finally
         {
             if (server != null) server.close();
             if (client != null) client.close();
             if (br != null) br.close();
             if (pw != null) pw.close();
         }
     }
 }

这里的服务器的功能非常简单,它接收客户端发来的消息,然后将消息“原封不动”的返回给客户端。当客户端发送“end”时,通信结束。

上面的代码基本上勾勒了TCP通信过程中,客户端和服务器端的主要框架,我们可以发现,上述的代码中,服务器端在任何时刻,都只能处理来自客户端的一个请求,它是串行处理的,不能并行,这和我们印象里的服务器处理方式不太相同,我们可以为服务器添加多线程,当一个客户端的请求进入后,我们就创建一个线程,来处理对应的请求。

改善后的服务器端代码如下:


代码如下:

多线程版本的TCP服务器端
 import java.net.*;
 import java.io.*;
 public class SmartTcpServer {
     public static void main(String[] args) throws IOException
     {
         ServerSocket server = new ServerSocket(5678);
         while(true)
         {
             Socket client = server.accept();
             Thread thread = new ServerThread(client);
             thread.start();
         }
     }
 }

class ServerThread extends Thread
 {
     private Socket socket = null;

public ServerThread(Socket socket)
     {
         this.socket = socket;
     }

public void run() {
         BufferedReader br = null;
         PrintWriter pw = null;
         try
         {
             br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             pw = new PrintWriter(socket.getOutputStream());
             while(true)
             {
                 String line = br.readLine();
                 pw.println("Response:" + line);
                 pw.flush();
                 if (line.equals("end")) break;
             }
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
         finally
         {
             if (socket != null)
                 try {
                     socket.close();
                 } catch (IOException e1) {
                     e1.printStackTrace();
                 }
             if (br != null)
                 try {
                     br.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             if (pw != null) pw.close();
         }
     }
 }

修改后的服务器端,就可以同时处理来自客户端的多个请求了。

在编程的过程中,我们会有“资源”的概念,例如数据库连接就是一个典型的资源,为了提升性能,我们通常不会直接销毁数据库连接,而是使用数据库连接池的方式来对多个数据库连接进行管理,已实现重用的目的。对于Socket连接来说,它也是一种资源,当我们的程序需要大量的Socket连接时,如果每个连接都需要重新建立,那么将会是一件非常没有效率的做法。

和数据库连接池类似,我们也可以设计TCP连接池,这里的思路是我们用一个数组来维持多个Socket连接,另外一个状态数组来描述每个Socket连接是否正在使用,当程序需要Socket连接时,我们遍历状态数组,取出第一个没被使用的Socket连接,如果所有连接都在使用,抛出异常。这是一种很直观简单的“调度策略”,在很多开源或者商业的框架中(Apache/Tomcat),都会有类似的“资源池”。

TCP连接池的代码如下:


代码如下:

一个简单的TCP连接池
 import java.net.*;
 import java.io.*;
 public class TcpConnectionPool {

private InetAddress address = null;
     private int port;
     private Socket[] arrSockets = null;
     private boolean[] arrStatus = null;
     private int count;

public TcpConnectionPool(InetAddress address, int port, int count)
     {
         this.address = address;
         this.port = port;
         this .count = count;
         arrSockets = new Socket[count];
         arrStatus = new boolean[count];

init();
     }

private void init()
     {
         try
         {
             for (int i = 0; i < count; i++)
             {
                 arrSockets[i] = new Socket(address.getHostAddress(), port);
                 arrStatus[i] = false;
             }
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }

public Socket getConnection()
     {
         if (arrSockets == null) init();
         int i = 0;
         for(i = 0; i < count; i++)
         {
             if (arrStatus[i] == false)
             {
                 arrStatus[i] = true;
                 break;
             }
         }
         if (i == count) throw new RuntimeException("have no connection availiable for now.");

return arrSockets[i];
     }

public void releaseConnection(Socket socket)
     {
         if (arrSockets == null) init();
         for (int i = 0; i < count; i++)
         {
             if (arrSockets[i] == socket)
             {
                 arrStatus[i] = false;
                 break;
             }
         }
     }

public void reBuild()
     {
         init();
     }

public void destory()
     {
         if (arrSockets == null) return;

for(int i = 0; i < count; i++)
         {
             try
             {
                 arrSockets[i].close();
             }
             catch(Exception ex)
             {
                 System.err.println(ex.getMessage());
                 continue;
             }
         }
     }
 }

UDP连接

UDP是一种和TCP不同的连接方式,它通常应用在对实时性要求很高,对准确定要求不高的场合,例如在线视频。UDP会有“丢包”的情况发生,在TCP中,如果Server没有启动,Client发消息时,会报出异常,但对UDP来说,不会产生任何异常。

UDP通信使用的两个类时DatagramSocket和DatagramPacket,后者存放了通信的内容。

下面是一个简单的UDP通信例子,同TCP一样,也分为Client和Server两部分,Client端代码如下:


代码如下:

UDP通信客户端
 import java.net.*;
 import java.io.*;
 public class UdpClient {

public static void main(String[] args)
     {
         try
         {
             InetAddress host = InetAddress.getLocalHost();
             int port = 5678;
             BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
             while(true)
             {
                 String line = br.readLine();
                 byte[] message = line.getBytes();
                 DatagramPacket packet = new DatagramPacket(message, message.length, host, port);
                 DatagramSocket socket = new DatagramSocket();
                 socket.send(packet);
                 socket.close();
                 if (line.equals("end")) break;
             }
             br.close();
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }
 }

Server端代码如下:


代码如下:

UDP通信服务器端
 import java.net.*;
 import java.io.*;
 public class UdpServer {

public static void main(String[] args)
     {
         try
         {
             int port = 5678;
             DatagramSocket dsSocket = new DatagramSocket(port);
             byte[] buffer = new byte[1024];
             DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
             while(true)
             {
                 dsSocket.receive(packet);
                 String message = new String(buffer, 0, packet.getLength());
                 System.out.println(packet.getAddress().getHostName() + ":" + message);
                 if (message.equals("end")) break;
                 packet.setLength(buffer.length);
             }
             dsSocket.close();
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }
 }

这里,我们也假设和TCP一样,当Client发出“end”消息时,认为通信结束,但其实这样的设计不是必要的,Client端可以随时断开,并不需要关心Server端状态。
多播(Multicast)

多播采用和UDP类似的方式,它会使用D类IP地址和标准的UDP端口号,D类IP地址是指224.0.0.0到239.255.255.255之间的地址,不包括224.0.0.0。

多播会使用到的类是MulticastSocket,它有两个方法需要关注:joinGroup和leaveGroup。

下面是一个多播的例子,Client端代码如下:


代码如下:

多播通信客户端
 import java.net.*;
 import java.io.*;
 public class MulticastClient {

public static void main(String[] args)
     {
         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
         try
         {
             InetAddress address = InetAddress.getByName("230.0.0.1");
             int port = 5678;
             while(true)
             {
                 String line = br.readLine();
                 byte[] message = line.getBytes();
                 DatagramPacket packet = new DatagramPacket(message, message.length, address, port);
                 MulticastSocket multicastSocket = new MulticastSocket();
                 multicastSocket.send(packet);
                 if (line.equals("end")) break;
             }
             br.close();
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }
 }

服务器端代码如下:


代码如下:

多播通信服务器端
 import java.net.*;
 import java.io.*;
 public class MulticastServer {

public static void main(String[] args)
     {
         int port = 5678;
         try
         {
             MulticastSocket multicastSocket = new MulticastSocket(port);
             InetAddress address = InetAddress.getByName("230.0.0.1");
             multicastSocket.joinGroup(address);
             byte[] buffer = new byte[1024];
             DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
             while(true)
             {
                 multicastSocket.receive(packet);
                 String message = new String(buffer, packet.getLength());
                 System.out.println(packet.getAddress().getHostName() + ":" + message);
                 if (message.equals("end")) break;
                 packet.setLength(buffer.length);
             }
             multicastSocket.close();
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }
 }

NIO(New IO)

NIO是JDK1.4引入的一套新的IO API,它在缓冲区管理、网络通信、文件存取以及字符集操作方面有了新的设计。对于网络通信来说,NIO使用了缓冲区和通道的概念。

下面是一个NIO的例子,和我们上面提到的代码风格有很大的不同。


代码如下:

NIO例子
 import java.io.*;
 import java.nio.*;
 import java.nio.channels.*;
 import java.nio.charset.*;
 import java.net.*;
 public class NewIOSample {

public static void main(String[] args)
     {
         String host="127.0.0.1";
         int port = 5678;
         SocketChannel channel = null;
         try
         {
             InetSocketAddress address = new InetSocketAddress(host,port);
             Charset charset = Charset.forName("UTF-8");
             CharsetDecoder decoder = charset.newDecoder();
             CharsetEncoder encoder = charset.newEncoder();

ByteBuffer buffer = ByteBuffer.allocate(1024);
             CharBuffer charBuffer = CharBuffer.allocate(1024);

channel = SocketChannel.open();
             channel.connect(address);

String request = "GET / \r\n\r\n";
             channel.write(encoder.encode(CharBuffer.wrap(request)));

while((channel.read(buffer)) != -1)
             {
                 buffer.flip();
                 decoder.decode(buffer, charBuffer, false);
                 charBuffer.flip();
                 System.out.println(charBuffer);
                 buffer.clear();
                 charBuffer.clear();
             }
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
         finally
         {
             if (channel != null)
                 try {
                     channel.close();
                 } catch (IOException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                 }
         }
     }
 }

上述代码会试图访问一个本地的网址,然后将其内容打印出来。

(0)

相关推荐

  • java中TCP/UDP详细总结

    TCP/UDP:TCP主要是面向连接的协议,它包含有建立和拆除连接,保证数据流的顺序和正确性等功能. 每次对TCP中间的数据操作相当于对一个数据流进行访问.它最典型的特征就是那三次握手的建立连接过程.Server端所要做的事情主要是建立一个通信的端点,然后等待客户端发送的请求.典型的处理步骤如下: 1. 构建一个ServerSocket实例,指定本地的端口.这个socket就是用来监听指定端口的连接请求的. 2.重复如下几个步骤: a. 调用socket的accept()方法来获得下面客户端的连

  • JAVA编程实现UDP网络通讯的方法示例

    本文实例讲述了JAVA编程实现UDP网络通讯的方法.分享给大家供大家参考,具体如下: UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议. 在OSI模型中,在第四层--传输层,处于IP协议的上一层.UDP有不提供数据包分组.组装和不能对数据包进行排序的缺点: 也就是说,当报文发送之后,是无法得知其是否安全完整到达的.UDP用来支持那些需要在计算机之间传输数据的网络应用. 采用UDP协议要先把数据定义成数据报(Datagram)并在数据报中指明数据所要达到

  • java 基础知识之网络通信(TCP通信、UDP通信、多播以及NIO)总结

    java 基础知识之网路通信总结 在这篇文章里,我们主要讨论如何使用Java实现网络通信,包括TCP通信.UDP通信.多播以及NIO. TCP连接 TCP的基础是Socket,在TCP连接中,我们会使用ServerSocket和Socket,当客户端和服务器建立连接以后,剩下的基本就是对I/O的控制了. 我们先来看一个简单的TCP通信,它分为客户端和服务器端. 客户端代码如下: 简单的TCP客户端 import java.net.*; import java.io.*; public class

  • java中UDP简单聊天程序实例代码

    学过计算机网络通信的都知道,计算机之间传送数据由两种,即TCP通信和UDP通信.TCP是可靠的面向连接的通信协议,二UDP是不可靠的面向无连接的通信协议. java中有基于TCP的网络套接字通信,也有基于UDP的用户数据报通信,UDP的信息传输速度快,但不可靠! 基于UDP通信的基本模式: (1)将数据打包,称为数据包(好比将信件装入信封一样),然后将数据包发往目的地. (2)接受别人发来的数据包(好比接收信封一样),然后查看数据包中的内容. 客户机 复制代码 代码如下: package com

  • Java基于socket服务实现UDP协议的方法

    本文实例讲述了Java基于socket服务实现UDP协议的方法.分享给大家供大家参考.具体如下: 示例1: 接收类: package com.socket.demo; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class UDPReceiveDemo { public static void main(String[] args) throw

  • JAVA编程实现TCP网络通讯的方法示例

    本文实例讲述了JAVA编程实现TCP网络通讯的方法.分享给大家供大家参考,具体如下: TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议. 由IETF的RFC 793定义,在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能. 基于TCP网络通讯实现的类主要有服务器端的ServerSocket用客户端的Socket. 通讯流程: 打开服务器,等待客户端连接-->客户端连接上服务器-->数据通讯. 代码

  • java编程实现基于UDP协议传输数据的方法

    本文实例讲述了java编程实现基于UDP协议传输数据的方法.分享给大家供大家参考,具体如下: UDP协议(User Datagram Protocol,用户数据报协议)不同于TCP协议,它是不可能靠的,但是它比TCP协议具有更快的传输速度,UDP发送的数据单元称为数据报,当网络传输UDP传输UDP数据报是无法保证数据能够到达目的地,也无法保证按发送的顺序到达目的地,也就是说先发送了"hello",再发送了"world",但接收方可能会先收到"world&q

  • java 中模拟UDP传输的发送端和接收端实例详解

    java 中模拟UDP传输的发送端和接收端实例详解 一.创建UDP传输的发送端 1.建立UDP的Socket服务: 2.将要发送的数据封装到数据包中: 3.通过UDP的Socket服务将数据包发送出去: 4.关闭Socket服务. import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class

  • 基于java TCP网络通信的实例详解

    JAVA中设计网络编程模式的主要有TCP和UDP两种,TCP是属于即时通信,UDP是通过数据包来进行通信,UDP当中就会牵扯到数据的解析和传送.在安全性能方面,TCP要略胜一筹,通信过程中不容易出现数据丢失的现象,有一方中断,两方的通信就会结束,UDP数据包传送的过程当中,一方中断,数据包有很大的可能丢失,还有可能传来的数据包的顺序是错乱的:在效率方面,UDP要比TCP快的不只是一点点的问题,若终端有解析数据方法的函数,数据包就会源源不断的传送过来,然后反馈回去.以上都是我自己的理解,下面是关于

  • java Socket UDP实例详解

    UDP编程示例 服务器端: package socket; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UDPServer { public static void main(String[] args) throws IOException { byte[] buf

  • Java基于UDP协议实现简单的聊天室程序

    最近比较闲,一直在抽空回顾一些Java方面的技术应用. 今天没什么事做,基于UDP协议,写了一个非常简单的聊天室程序. 现在的工作,很少用到socket,也算是对Java网络编程方面的一个简单回忆. 先看一下效果: 实现的效果可以说是非常非常简单,但还是可以简单的看到一个实现原理.  "聊天室001"的用户,小红和小绿相互聊了两句,"聊天室002"的小黑无人理会,在一旁寂寞着. 看一下代码实现: 1.首先是消息服务器的实现,功能很简单: •将客户端的信息(进入了哪一

  • 浅谈java的TCP和UDP编程(附实例讲解)

    TCP 客户端: import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class MyClient { public static void main(String[] args) throws Exception{ Socket socket = null; BufferedReader in = n

随机推荐