`

JAVA套接字(Socket)四 简单例子

阅读更多
一个简单示例
1. 背景

我们将在本部分讨论的示例将阐明在 Java 代码中如何使用 Socket 和 ServerSocket。客户机用Socket 连接到服务器。服务器用 ServerSocket 在端口 3000 侦听。客户机请求服务器 C: 驱动器上的文件内容。
为清楚起见,我们把示例分解成客户机端和服务器端。最后我们将把它们组合起来以使您能看到整体模样。
我们在使用 JDK 1.2 的 IBM VisualAge for Java 3.5 上开发这些代码。要自己创建这个示例,您应有完好的 JDK 1.1.7 或更高版本。客户机和服务器将只在一台机器上运行,所以您不必担心是否有一个可用的网络。

2. 创建 RemoteFileClient 类
这里是 RemoteFileClient 类的结构:
import java.io.*;
import java.net.*;

public class RemoteFileClient {
    protected String hostIp;
    protected int hostPort;
    protected BufferedReader socketReader;
    protected PrintWriter socketWriter;

    public RemoteFileClient(String aHostIp, int aHostPort) {
        hostIp = aHostIp;
        hostPort = aHostPort;
    }
    public static void main(String[] args) {
    }
    public void setUpConnection() {
    }
    public String getFile(String fileNameToGet) {
    }
    public void tearDownConnection() {
    }
}


首先我们导入 java.net 和java.io。java.net 包为您提供您需要的套接字工具。java.io 包为您提供对流进行读写的工具,这是您与 TCP 套接字通信的唯一途径。
我们给我们的类实例变量以支持对套接字流的读写和存储我们将连接到的远程主机的详细信息。
我们类的构造器有两个参数:远程主机的 IP 地址和端口号各一个,而且构造器将它们赋给实例变量。
我们的类有一个 main() 方法和三个其它方法。稍后我们将探究这些方法的细节。现在您只需知道setUpConnection() 将连接到远程服务器,getFile() 将向远程服务器请求fileNameToGet 的内容以及tearDownConnection() 将从远程服务器上断开。

3. 实现 main()
这里我们实现 main() 方法,它将创建 RemoteFileClient 并用它来获取远程文件的内容,然后打印结果:
public static void main(String[] args) {
    RemoteFileClient remoteFileClient = new RemoteFileClient("127.0.0.1", 3000);
    remoteFileClient.setUpConnection();
    String fileContents =
        remoteFileClient.getFile("C:\\WINNT\\Temp\\RemoteFile.txt");
    remoteFileClient.tearDownConnection();

    System.out.println(fileContents);
}


main() 方法用主机的 IP 地址和端口号实例化一个新RemoteFileClient(客户机)。然后,我们告诉客户机建立一个到主机的连接(稍后有更详细的讨论)。接着,我们告诉客户机获取主机上一个指定文件的内容。最后,我们告诉客户机断开它到主机的连接。我们把文件内容打印到控制台,只是为了证明一切都是按计划进行的。

4. 建立连接
这里我们实现 setUpConnection() 方法,它将创建我们的 Socket 并让我们访问该套接字的流:
public void setUpConnection() {
    try {
        Socket client = new Socket(hostIp, hostPort);

        socketReader = new BufferedReader(
        		   new InputStreamReader(client.getInputStream()));
        socketWriter = new PrintWriter(client.getOutputStream());

    } catch (UnknownHostException e) {
        System.out.println("Error setting up socket connection: unknown host at " + hostIp + ":" + hostPort);
    } catch (IOException e) {
        System.out.println("Error setting up socket connection: " + e);
    }
}

setUpConnection() 方法用主机的 IP 地址和端口号创建一个Socket:
Socket client = new Socket(hostIp, hostPort);


我们把 Socket 的InputStream 包装进BufferedReader 以使我们能够读取流的行。然后,我们把Socket 的 OutputStream 包装进 PrintWriter 以使我们能够发送文件请求到服务器:
socketReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
socketWriter = new PrintWriter(client.getOutputStream());


请记住我们的客户机和服务器只是来回传送字节。客户机和服务器都必须知道另一方即将发送的是什么以使它们能够作出适当的响应。在这个案例中,服务器知道我们将发送一条有效的文件路径。
当您实例化一个 Socket 时,将抛出UnknownHostException。这里我们不特别处理它,但我们打印一些信息到控制台以告诉我们发生了什么错误。同样地,当我们试图获取Socket 的 InputStream 或 OutputStream 时,如果抛出了一个一般IOException,我们也打印一些信息到控制台。这是本教程的一般做法。在产品代码中,我们应该做得更完善些。

5. 与主机交谈
这里我们实现 getFile() 方法,它将告诉服务器我们想要什么文件并在服务器传回其内容时接收该内容。
public String getFile(String fileNameToGet) {
    StringBuffer fileLines = new StringBuffer();

    try {
        socketWriter.println(fileNameToGet);
        socketWriter.flush();

        String line = null;
        while ((line = socketReader.readLine()) != null)
            fileLines.append(line + "\n");
    } catch (IOException e) {
        System.out.println("Error reading from file: " + fileNameToGet);
    }

    return fileLines.toString();
}


对 getFile() 方法的调用要求一个有效的文件路径String。它首先创建名为fileLines 的StringBuffer,fileLines 用于存储我们读自服务器上的文件的每一行。
StringBuffer fileLines = new StringBuffer();


在 try{}catch{} 块中,我们用PrintWriter 把请求发送到主机,PrintWriter 是我们在创建连接期间建立的。
socketWriter.println(fileNameToGet);
socketWriter.flush();


请注意这里我们是 flush() 该PrintWriter,而不是关闭它。这迫使数据被发送到服务器而不关闭Socket。
一旦我们已经写到 Socket,我们就希望有一些响应。我们不得不在Socket 的 InputStream 上等待它,我们通过在while 循环中调用BufferedReader 上的readLine() 来达到这个目的。我们把每一个返回行附加到fileLines StringBuffer(带有一个换行符以保护行):
String line = null;
while ((line = socketReader.readLine()) != null)
    fileLines.append(line + "\n");


6. 断开连接
这里我们实现 tearDownConnection() 方法,它将在我们使用完毕连接后负责“清除”:
public void tearDownConnection() {
    try {
        socketWriter.close();
        socketReader.close();
    } catch (IOException e) {
        System.out.println("Error tearing down socket connection: " + e);
    }
}


tearDownConnection() 方法只是分别关闭我们在Socket 的 InputStream 和 OutputStream 上创建的BufferedReader 和PrintWriter。这样做会关闭我们从Socket 获取的底层流,所以我们必须捕捉可能的IOException。
7. 总结一下客户机
我们的类研究完了。在我们继续往前讨论服务器端的情况之前,让我们回顾一下创建和使用 Socket 的步骤:
用您想连接的机器的 IP 地址和端口实例化 Socket(如有问题则抛出 Exception)。

获取 Socket 上的流以进行读写。

把流包装进 BufferedReader/PrintWriter 的实例,如果这样做能使事情更简单的话。

对 Socket 进行读写。

关闭打开的流。
   附:RemoteFileClient 的代码清单
import java.io.*;
import java.net.*;

public class RemoteFileClient {
    protected BufferedReader socketReader;
    protected PrintWriter socketWriter;
    protected String hostIp;
    protected int hostPort;

    public RemoteFileClient(String aHostIp, int aHostPort) {
        hostIp = aHostIp;
        hostPort = aHostPort;
    }
    public String getFile(String fileNameToGet) {
        StringBuffer fileLines = new StringBuffer();

        try {
            socketWriter.println(fileNameToGet);
            socketWriter.flush();

            String line = null;
            while ((line = socketReader.readLine()) != null)
                fileLines.append(line + "\n");
        } catch (IOException e) {
            System.out.println("Error reading from file: " + fileNameToGet);
        }

        return fileLines.toString();
    }
    public static void main(String[] args) {
        RemoteFileClient remoteFileClient = new RemoteFileClient("127.0.0.1", 3000);
        remoteFileClient.setUpConnection();
        String fileContents = remoteFileClient.getFile("C:\\WINNT\\Temp\\RemoteFile.txt");
        remoteFileClient.tearDownConnection();

        System.out.println(fileContents);
    }
    public void setUpConnection() {
        try {
            Socket client = new Socket(hostIp, hostPort);

            socketReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
            socketWriter = new PrintWriter(client.getOutputStream());

        } catch (UnknownHostException e) {
            System.out.println("Error setting up socket connection: unknown host at " + hostIp + ":" + hostPort);
        } catch (IOException e) {
            System.out.println("Error setting up socket connection: " + e);
        }
    }
    public void tearDownConnection() {
        try {
            socketWriter.close();
            socketReader.close();
        } catch (IOException e) {
            System.out.println("Error tearing down socket connection: " + e);
        }
    }
}

8. 创建 RemoteFileServer 类
这里是 RemoteFileServer 类的结构:
import java.io.*;
import java.net.*;

public class RemoteFileServer {
    protected int listenPort = 3000;
    public static void main(String[] args) {
    }
    public void acceptConnections() {
    }
    public void handleConnection(Socket incomingConnection) {
    }
}


跟客户机中一样,我们首先导入 java.net 的 java.io。接着,我们给我们的类一个实例变量以保存端口,我们从该端口侦听进入的连接。缺省情况下,端口是 3000。
我们的类有一个 main() 方法和两个其它方法。稍后我们将探究这些方法的细节。现在您只需知道 acceptConnections() 将允许客户机连接到服务器以及 handleConnection() 与客户机 Socket 交互以将您所请求的文件的内容发送到客户机。
9. 实现 main()
这里我们实现 main() 方法,它将创建 RemoteFileServer 并告诉它接受连接:
public static void main(String[] args) {
    RemoteFileServer server = new RemoteFileServer();
    server.acceptConnections();
}


服务器端的 main() 方法甚至比客户机端的更简单。我们实例化一个新 RemoteFileServer,它将在缺省侦听端口上侦听进入的连接请求。然后我们调用 acceptConnections() 来告诉该 server 进行侦听。
10. 接受连接
这里我们实现 acceptConnections() 方法,它将创建一个 ServerSocket 并等待连接请求:
public void acceptConnections() {
    try {
        ServerSocket server = new ServerSocket(listenPort);
        Socket incomingConnection = null;
        while (true) {
            incomingConnection = server.accept();
            handleConnection(incomingConnection);
        }
    } catch (BindException e) {
        System.out.println("Unable to bind to port " + listenPort);
    } catch (IOException e) {
        System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort);
    }
}


acceptConnections() 用欲侦听的端口号来创建 ServerSocket。然后我们通过调用该 ServerSocket 的 accept() 来告诉它开始侦听。accept() 方法将造成阻塞直到来了一个连接请求。此时,accept() 返回一个新的 Socket,这个 Socket 绑定到服务器上一个随机指定的端口,返回的 Socket 被传递给 handleConnection()。请注意我们在一个无限循环中处理对连接的接受。这里不支持任何关机。
无论何时如果您创建了一个无法绑定到指定端口(可能是因为别的什么控制了该端口)的 ServerSocket,Java 代码都将抛出一个错误。所以这里我们必须捕捉可能的 BindException。就跟在客户机端上时一样,我们必须捕捉 IOException,当我们试图在 ServerSocket 上接受连接时,它就会被抛出。请注意,您可以通过用毫秒数调用 setSoTimeout() 来为 accept() 调用设置超时,以避免实际长时间的等待。调用 setSoTimeout() 将使 accept() 经过指定占用时间后抛出 IOException。

11. 处理连接
这里我们实现 handleConnection() 方法,它将用连接的流来接收输入和写输出:
public void handleConnection(Socket incomingConnection) {
    try {
        OutputStream outputToSocket = incomingConnection.getOutputStream();
        InputStream inputFromSocket = incomingConnection.getInputStream();

        BufferedReader streamReader =
            new BufferedReader(new InputStreamReader(inputFromSocket));

        FileReader fileReader = new FileReader(new File(streamReader.readLine()));

        BufferedReader bufferedFileReader = new BufferedReader(fileReader);
        PrintWriter streamWriter =
            new PrintWriter(incomingConnection.getOutputStream());
        String line = null;
        while ((line = bufferedFileReader.readLine()) != null) {
            streamWriter.println(line);
        }

        fileReader.close();
        streamWriter.close();
        streamReader.close();
    } catch (Exception e) {
        System.out.println("Error handling a client: " + e);
    }
}


跟在客户机中一样,我们用 getOutputStream() 和 getInputStream() 来获取与我们刚创建的 Socket 相关联的流。跟在客户机端一样,我们把 InputStream 包装进 BufferedReader,把 OutputStream 包装进 PrintWriter。在服务器端上,我们需要添加一些代码,用来读取目标文件和把内容逐行发送到客户机。这里是重要的代码:
      FileReader fileReader = new FileReader(new File(streamReader.readLine()));
        BufferedReader bufferedFileReader = new BufferedReader(fileReader);
        String line = null;
        while ((line = bufferedFileReader.readLine()) != null) {
             streamWriter.println(line);
        }


这些代码值得详细解释。让我们一点一点来看:
FileReader fileReader = new FileReader(new File(streamReader.readLine()));


首先,我们使用 Socket 的 InputStream 的 BufferedReader。我们应该获取一条有效的文件路径,所以我们用该路径名构造一个新 File。我们创建一个新 FileReader 来处理读文件的操作。
BufferedReader bufferedFileReader = new BufferedReader(fileReader);


这里我们把 FileReader 包装进 BufferedReader 以使我们能够逐行地读该文件。
接着,我们调用 BufferedReader 的 readLine()。这个调用将造成阻塞直到有字节到来。我们获取一些字节之后就把它们放到本地的 line 变量中,然后再写出到客户机上。完成读写操作之后,我们就关闭打开的流。
请注意我们在完成从 Socket 的读操作之后关闭 streamWriter 和 streamReader。您或许会问我们为什么不在读取文件名之后立刻关闭 streamReader。原因是当您这样做时,您的客户机将不会获取任何数据。如果您在关闭 streamWriter 之前关闭 streamReader,则您可以往 Socket 写任何东西,但却没有任何数据能通过通道(通道被关闭了)。

12. 总结一下服务器
在我们接着讨论另一个更实际的示例之前,让我们回顾一下创建和使用 ServerSocket 的步骤:
用一个您想让它侦听传入客户机连接的端口来实例化一个 ServerSocket(如有问题则抛出 Exception)。

调用 ServerSocket 的 accept() 以在等待连接期间造成阻塞。

获取位于该底层 Socket 的流以进行读写操作。

按使事情简单化的原则包装流。

对 Socket 进行读写。

关闭打开的流(并请记住,永远不要在关闭 Writer 之前关闭 Reader)。
  附: RemoteFileServer 的完整的代码清单
import java.io.*;
import java.net.*;

public class RemoteFileServer {
    int listenPort;
    public RemoteFileServer(int aListenPort) {
        listenPort = aListenPort;
    }
    public void acceptConnections() {
        try {
            ServerSocket server = new ServerSocket(listenPort);
            Socket incomingConnection = null;
            while (true) {
                incomingConnection = server.accept();
                handleConnection(incomingConnection);
            }
        } catch (BindException e) {
            System.out.println("Unable to bind to port " + listenPort);
        } catch (IOException e) {
            System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort);
        }
    }
    public void handleConnection(Socket incomingConnection) {
        try {
            OutputStream outputToSocket = incomingConnection.getOutputStream();
            InputStream inputFromSocket = incomingConnection.getInputStream();

            BufferedReader streamReader = new BufferedReader(new InputStreamReader(inputFromSocket));

            FileReader fileReader = new FileReader(new File(streamReader.readLine()));

            BufferedReader bufferedFileReader = new BufferedReader(fileReader);
            PrintWriter streamWriter = new PrintWriter(incomingConnection.getOutputStream());
            String line = null;
            while ((line = bufferedFileReader.readLine()) != null) {
                streamWriter.println(line);
            }

            fileReader.close();
            streamWriter.close();
            streamReader.close();
        } catch (Exception e) {
            System.out.println("Error handling a client: " + e);
        }
    }
    public static void main(String[] args) {
        RemoteFileServer server = new RemoteFileServer(3000);
        server.acceptConnections();
    }
}



ref:http://blog.csdn.net/m13666368773/article/details/7630621
分享到:
评论

相关推荐

    java基于UNIX域套接字(unix domain socket)连接redis

    为了优化网络通信,有时我们会选择使用UNIX域套接字(UNIX Domain Socket,简称UDS)来代替传统的TCP/IP套接字进行进程间通信(IPC)。本篇将详细讲解如何在Java环境下,利用UNIX域套接字连接并操作Redis,以及涉及...

    一个经典的java 套接字传输范例

    Java套接字(Socket)是网络编程中的基本概念,它为两台计算机之间的通信提供了低级别的接口。在Java中,套接字允许客户端应用程序连接到服务器,并通过网络发送和接收数据。下面,我们将深入探讨Java套接字传输的...

    有关java 的socket套接字实例

    有关套接字的例子,本人工作多年,在linux环境下,多进程通信方式是采用socket套接字,这个实例对学习socket 套接字的朋友来说相当有用,祝你们在通信领域里有所为,为中国软件事业做应有的贡献!软友们加油!!!!...

    java socket 客户端和服务端例子

    Java Socket库提供了一种标准的方式来创建和使用这些套接字。 服务端(server)程序通常会先启动,它会监听特定的IP地址和端口号,等待客户端的连接请求。一旦有客户端发起连接,服务端会创建一个Socket实例来处理...

    Java TCP/IP Socket编程

    `Java+TCPIP+Socket编程(中文版).pdf`这个文件很可能包含了详细的教程和示例代码,可以帮助深入理解Java Socket编程的各种细节,包括如何设置套接字选项、处理多线程并发连接、使用NIO(非阻塞I/O)优化性能等高级...

    网上收集的多个Socket编程经典例子源码

    - Socket分为流式套接字(TCP)和数据报套接字(UDP)。TCP提供面向连接的、可靠的、基于字节流的通信,而UDP则是无连接的、不可靠的、基于数据报的通信。 2. **TCP Socket编程**: - TCP Socket编程主要涉及三次...

    java socket programming example

    Java套接字编程是网络通信的核心技术之一,它允许Java应用程序通过网络进行双向通信。在本示例中,我们探讨的是一份简单的Java Socket程序,其中融入了线程的概念,这意味着我们可以同时处理多个连接,提高了服务端...

    java_python_socket.zip

    Python的socket模块提供了低级别的套接字操作,可以创建服务器端和客户端。 ```python # Python客户端示例 import socket def python_client(): client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ...

    线程与socket例子.rar_java_layersnut_socket

    接下来,我们讨论“Socket”(套接字)。Socket是网络编程中的重要概念,它为两台计算机之间的通信提供了一个端点。在Java中,Socket类位于java.net包下,提供了客户端和服务端的连接和数据传输功能。`socket1`和`...

    java socket通讯程序源码

    Socket,通常被称为套接字,它是网络通信中的端点,用于标识一台机器上的一个进程,并允许它与其他进程进行通信。在TCP/IP协议栈中,Socket分为两种类型:流式Socket(Stream Sockets,对应于TCP)和数据报Socket...

    java socket

    服务器端使用`ServerSocket`类创建一个监听套接字,通过`bind()`方法绑定到特定的IP地址和端口号,然后调用`accept()`方法等待客户端的连接。当有客户端连接时,`accept()`方法会返回一个新的Socket实例,服务器通过...

    java IO流+socket源码 实现简单文本传输

    Socket,又称套接字,是网络通信的基础。在Java中,Socket类和ServerSocket类分别用于客户端和服务器端的通信。通过Socket,我们可以建立TCP连接,实现可靠的、双向的数据传输。Socket通信通常包括以下步骤:服务器...

    Java中使用套接字的案例代码清单.pdf

    Java中的套接字(Socket)是网络编程中的基础组件,用于实现两台机器之间的通信。在Java中,套接字类提供了创建客户端和服务器端连接的能力。以下是对标题和描述中涉及知识点的详细解释: 1. **Socket类**:在Java...

    Java网络socket编程详解—有简单例子

    本文将深入讲解如何使用Java进行Socket编程,包括面向套接字的编程思路,以及创建TCP协议的服务器和客户端程序的具体步骤。 首先,我们需要理解Socket的基本概念。Socket在Java中是一个接口,它代表了网络上的一个...

    java socket编程实例(出自《java大学教程》)

    Java套接字(Socket)编程是Java网络编程的基础,它提供了客户端与服务器之间的通信机制。在《Java大学教程》中,通常会通过实例来详细解释和演示这些概念。本实例集中,我们关注的是三个关键的Socket编程示例,旨在...

    java网络编程使用的简单例子

    7. **异常处理**:在进行网络编程时,必须考虑到网络问题可能导致的各种异常,如`UnknownHostException`(找不到主机)、`IOException`(输入/输出错误)和`SocketException`(套接字异常)。因此,编写健壮的网络...

    JAVA Socket 网络编程教程

    Socket,也被称为套接字,是网络通信中的一个重要接口,它为两台计算机提供了一个低级别的、进程到进程的通信机制。在Java中,Socket类位于java.net包下,提供了面向连接的TCP协议的实现。 二、TCP与UDP协议 1. TCP...

    socketdemo 一个用来学习socket入门的例子

    - `java.net.ServerSocket` 类用于创建服务器端监听套接字,等待客户端的连接请求。 - `java.io.InputStream` 和 `java.io.OutputStream` 分别用于读取和写入Socket连接上的数据。 3. **SocketDemo的实现流程**:...

    JSocket_Server.rar_jSocket server_java server socket_java socket

    首先,让我们深入了解一下Java服务器套接字(ServerSocket)和Java套接字(Socket)的概念。Java的`java.net.ServerSocket` 类用于监听客户端的连接请求。创建一个`ServerSocket` 实例并指定一个端口号,服务器就会...

Global site tag (gtag.js) - Google Analytics