如何实现Java无缝socket编程

来源:互联网 发布:广联达软件开发怎么样 编辑:程序博客网 时间:2024/06/09 19:00

为什么Java平台能区得如此大的成功呢?它的一个主要原因是因为它从一开始就获得了网络的支持。在这篇文章中,我将向大家介绍如何使用Java sockets实现基本的网络编程。


什么是sockets

TCP/IP协议是一个非常重要的工具,它在企业应用软件中的组织分布式计算和通信方面有广泛的应用。TCP协议主要处理传输控制任务,而IP协议主要服务于封装的TCP包数据,提供网络和寻址能力。还有另外的一个传输协议层——用户数据报协议(UDP),它是一种无连接数据包协议。被压缩到IP包中。因为UDP包传输不需要连接,所以,它是一种没有确认信息的消息机制。虽然它的速度非常快,但是不可靠。

在任何数据传输前都必须在活动的TCP连接的两端打开sockets。从Java程序员的观点来看,sockets是一个发送数据的通道,也是一个接收数据的通道,它可以接收从其它的计算机上的另一个应用程序发送过来的数据。

为了对TCP连接进行初始化,你可以使用标准的Java库函数java.net包中的类。这个包中包含sockets在任何环境下工作所需要的类,所以你的Java真正地保留了平台独立性。

调用java.net的类被转换成调用操作系统的API,所有TCP/IP实现的细节都被软件开发人员隐藏了。对于TCP sockets,你需要使用InetAddress、Socket和 ServerSocket包。对于UDPsockets,你需要使用DatagramSocket类和DatagramPacket类。

你甚至可以在TCP或者UDP的基础是创建新的网络协议。为了达到这个目的,你需要使用特殊的类和界面,包括SocketImplFactory、 SocketImpl和 DatagramSocketImpl。


服务器端

我下面将写一个小的客户/服务器应用程序,其中包括在服务器上不断监听来到的连接请求,和在客户端应用程序连接服务器的进程和传输数据。这两个程序是独立运行的,它们要装在不同的主机上。

最开始,服务器程序创建一个新的ServerSocket对象,这个对象是用来监听指定的端口的。(在编写服务器应用程序的时候,需要选择一个没有被其它服务占用的端口。)下面的例子中,服务器监听了端口4444:

import java.io.*;

import java.net.*;

try {

    serverSocket = new ServerSocket(4444);

} catch (IOException e) {

    System.out.println("Could not listen on port: 4444");

    System.exit(-1);

}

ServerSocket是java.net的一个类,它提供了一个在服务器端独立的实现客户/服务器socket连接。如果我们不能监听指定的端口,ServerSocket构造器将抛出一个异常(例如,当端口被占用的时候将抛出一个异常)。

如果服务器能与端口成功的绑定,那么ServerSocket对象就被创建了,这时候,下一步就是——接受来自客户端的连接。

Socket clientSocket = null;

try {

    clientSocket = serverSocket.accept();

} catch (IOException e) {

    System.out.println("Accept failed: 4444");

    System.exit(-1);

}

Accept方法一直处于等待状态,直到客户端开始要求与主机和该服务器所指定的端口进行连接的时候。当需要连接并成功创建连接的时候,accept方法返回一个新的Socket对象,这个对象与相同的本地端口绑定,并包含它的客户端的远程地址和远程端口设置。

服务器用这个新的Socket与客户端通信,同时继续在初始的ServerSocket上的监听客户端的连接请求。(这个特殊的程序版本不需要监听更多的客户连接请求。)


大部分客户端请求能进入相同的端口,因此也能进入相同的ServerSocket。客户端的连接请求在端口上进行排队,所以服务器可以继续接受请求;然而,服务器可以通过使用线程同时为它们服务(例如,每个客户端连接对应于一个线程)。这个逻辑经常用在多连接Java服务器应用程序上。看看下面的例子:

while (true) {

    accept a connection ;

    create a thread to deal with the client ;

end while

新线程从客户端读取数据,并将数据写回客户端。当服务器成功地与客户端建立连接之后,服务器端可以使用下面这段代码与客户端通信:

PrintWriter out = new PrintWriter(

                      clientSocket.getOutputStream(), true);

BufferedReader in = new BufferedReader(

                        new InputStreamReader(

                            clientSocket.getInputStream()));

String inputLine, outputLine;

while ((inputLine = in.readLine()) != null) {  

    outputLine = inputLine;

    out.println(outputLine);

    if outputLine.equals("Bye."))

        break;

}

既然这样,服务器将在回复的时候复制所有来到的信息,直到它收到字符串“Bye”。只要服务器与客户端一直在相互通信,服务器就要从socket中读取信息,并将信息写回socket,就这样在服务器和客户端之间来来回回的发送消息。在这之后,服务器将终止所有的流并终止连接。

out.close();

in.close();

clientSocket.close();

serverSocket.close();


客户端

当你开始写客户端程序的时候,服务器应该已经在运行了,并在监听端口等待客户端所发送的连接请求。客户端程序首先要做的就是打开socket使它与运行在主机的服务器和指定的端口进行连接。

import java.io.*;

import java.net.*;

theSocket = new Socket("hostname.example.com", 4444);

out = new PrintWriter(theSocket.getOutputStream(), true);

in = new BufferedReader(new InputStreamReader(

                            theSocket.getInputStream()));

当你运行这个程序的时候,在Socket构造器中将主机名改成你所在的网络中的机器名。这个计算机是你运行服务器应用程序的地方。当使用socket进行通信时,这个程序也要指定端口号为4444。

这是一个远程端口号(例如:根据服务器端的端口数量选择),它也是服务器正在监听的端口。客户端的socket一定要是未被占用的任意端口(例如,在客户端计算机上的某个端口)。

下面是while循环,这个循环实现了客户端与服务器之间的通信。客户端应用程序将从键盘上读取输入信息(或者标准输入),同时也将这些信息发送给服务器,所以服务器将返回同样的字符串。

BufferedReader stdIn = new BufferedReader(

                                   new InputStreamReader(System.in));

String userInput;

while ((userInput = stdIn.readLine()) != null) {

      if (fromServer.equals("Bye."))

            break;

      out.println(userInput);

      System.out.println("echo: " + in.readLine());

}

注意,当服务器说“Bye”的时候,客户端应该终止连接。为了实现这个目的,在“Bye”传输到服务器并返回之后,你需要在客户端说同样的字符串。客户端必须关闭所有的流和连接。

out.close();

in.close();

stdIn.close();

theSocket.close();


结论

Java.net包为网络编程提供了强大且灵活的组织结构。如果你想了解这个包中所提供的类的话,我建议你多引用这个包。


原创粉丝点击