`

JAVA套接字(Socket)多线程例子

阅读更多
一个多线程的示例
1. 介绍

前面的示例教给您基础知识,但并不能令您更深入。如果您到此就停止了,那么您一次只能处理一台客户机。原因是 handleConnection() 是一个阻塞方法。只有当它完成了对当前连接的处理时,服务器才能接受另一个客户机。在多数时候,您将需要(也有必要)一个多线程服务器。
要开始同时处理多台客户机,并不需要对 RemoteFileServer 作太多改变。事实上,要是我们前面讨论过待发(backlog),那我们就只需改变一个方法,虽然我们将需要创建一些新东西来处理进入的连接。这里我们还将向您展示 ServerSocket 如何处理众多等待(备份)使用服务器的客户机。本示例对线程的低效使用,所以请耐心点。

2. 接受(太多)连接
这里我们实现改动过的 acceptConnections() 方法,它将创建一个能够处理待发请求的 ServerSocket,并告诉 ServerSocket 接受连接:
public void acceptConnections() {
        try {
        ServerSocket server = new ServerSocket(listenPort, 5);
        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);
    }
}


新的 server 仍然需要 acceptConnections(),所以这些代码实际上是一样的。突出显示的行表示一个重大的不同。对这个多线程版,我们现在可以指定客户机请求的最大数目,这些请求都能在实例化 ServerSocket 期间处于待发状态。如果我们没有指定客户机请求的最大数目,则我们假设使用缺省值 50。
这里是它的工作机制。假设我们指定待发数(backlog 值)是 5 并且有五台客户机请求连接到我们的服务器。我们的服务器将着手处理第一个连接,但处理该连接需要很长时间。由于我们的待发值是 5,所以我们一次可以放五个请求到队列中。我们正在处理一个,所以这意味着还有其它五个正在等待。等待的和正在处理的一共有六个。当我们的服务器仍忙于接受一号连接(记住队列中还有 2―6 号)时,如果有第七个客户机提出连接申请,那么,该第七个客户机将遭到拒绝。我们将在带有连接池服务器示例中说明如何限定能同时连接的客户机数目。

3. 处理连接:第 1 部分
这里我们将讨论 handleConnection() 方法的结构,这个方法生成一个新的 Thread 来处理每个连接。我们将分两部分讨论这个问题。这一屏我们将着重该方法本身,然后在下一屏研究该方法所使用的 ConnectionHandler 助手类的结构。
public void handleConnection(Socket connectionToHandle) {
     new Thread(new ConnectionHandler(connectionToHandle)).start();
}


我们对 RemoteFileServer 所做的大改动就体现在这个方法上。我们仍然在服务器接受一个连接之后调用 handleConnection(),但现在我们把该 Socket 传递给 ConnectionHandler 的一个实例,它是 Runnable 的。我们用 ConnectionHandler 创建一个新 Thread 并启动它。ConnectionHandler 的 run() 方法包含Socket 读/写和读 File 的代码,这些代码原来在 RemoteFileServer 的 handleConnection() 中。

4. 处理连接:第 2 部分
这里是 ConnectionHandler 类的结构:
import java.io.*;
import java.net.*;

public class ConnectionHandler implements Runnable{
   Socket socketToHandle;

   public ConnectionHandler(Socket aSocketToHandle) {
      socketToHandle = aSocketToHandle;
   }

   public void run() {
   }
}


这个助手类相当简单。跟我们到目前为止的其它类一样,我们导入 java.net 和 java.io。该类只有一个实例变量 socketToHandle,它保存由该实例处理的 Socket。
类的构造器用一个 Socket 实例作参数并将它赋给 socketToHandle。
请注意该类实现了 Runnable 接口。实现这个接口的类都必须实现 run() 方法,我们的类就是这样做的。稍后我们将探究 run() 的细节。现在只需知道它将实际处理连接,所用的代码跟我们先前在 RemoteFileServer 类中看到的是一样的。

5. 实现 run()
这里我们实现 run() 方法,它将攫取我们的连接的流,用它来读写该连接,并在任务完成之后关闭它:
   public void run() {
        try {
            PrintWriter streamWriter = new PrintWriter(socketToHandle.getOutputStream());
            BufferedReader streamReader =
                new BufferedReader(new InputStreamReader(socketToHandle.getInputStream()));

            String fileToRead = streamReader.readLine();
            BufferedReader fileReader = new BufferedReader(new FileReader(fileToRead));

            String line = null;
            while ((line = fileReader.readLine()) != null)
                streamWriter.println(line);

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


ConnectionHandler 的 run() 方法所做的事情就是 RemoteFileServer 上的 handleConnection() 所做的事情。首先,我们把 InputStream 和 OutputStream 分别包装(用 Socket 的 getOutputStream() 和 getInputStream())进 BufferedReader 和 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);
        }


请记住我们应该从客户机获取一条有效的文件路径,这样用该路径名构造一个新 File,把它包装进 FileReader 以处理读文件的操作,然后把它包装进 BufferedReader 以让我们逐行地读该文件。我们在 while 循环中调用 BufferedReader 上的 readLine() 直到不再有要读的行。请记注,对 readLine() 的调用将造成阻塞,直到有字节来到为止。我们获取一些字节之后就把它们放到本地的 line 变量中,然后写出到客户机上。完成读写操作之后,我们关闭打开的流。

6. 总结一下多线程服务器
我们的多线程服务器研究完了。在我们接着讨论带有连接池示例之前,让我们回顾一下创建和使用“多线程版”的服务器的步骤:
修改 acceptConnections() 以用缺省为 50(或任何您想要的大于 1 的指定数字)实例化 ServerSocket。
修改 ServerSocket 的 handleConnection() 以用 ConnectionHandler 的一个实例生成一个新的 Thread。

借用 RemoteFileServer 的 handleConnection() 方法的代码实现 ConnectionHandler 类。
附: MultithreadedRemoteFileServer 的完整代码清单
import java.io.*;
import java.net.*;

public class MultithreadedRemoteFileServer {
    protected int listenPort;
    public MultithreadedRemoteFileServer(int aListenPort) {
        listenPort = aListenPort;
    }
    public void acceptConnections() {
        try {
            ServerSocket server = new ServerSocket(listenPort, 5);
            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 connectionToHandle) {
        new Thread(new ConnectionHandler(connectionToHandle)).start();
    }
    public static void main(String[] args) {
        MultithreadedRemoteFileServer server = new MultithreadedRemoteFileServer(3000);
        server.acceptConnections();
    }
}

ConnectionHandler 的完整代码清单
import java.io.*;
import java.net.*;

public class ConnectionHandler implements Runnable {
    protected Socket socketToHandle;
    public ConnectionHandler(Socket aSocketToHandle) {
        socketToHandle = aSocketToHandle;
    }
    public void run() {
        try {
            PrintWriter streamWriter = new PrintWriter(socketToHandle.getOutputStream());
            BufferedReader streamReader = new BufferedReader(new InputStreamReader(socketToHandle.getInputStream()));

            String fileToRead = streamReader.readLine();
            BufferedReader fileReader = new BufferedReader(new FileReader(fileToRead));

            String line = null;
            while ((line = fileReader.readLine()) != null)
                streamWriter.println(line);

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


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

相关推荐

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

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

    C#Socket多线程编程实例

    C# Socket多线程编程实例是一个讲解如何使用C#语言结合多线程技术来实现网络通信的具体例子。 C#(读作“看井”)是由微软公司推出的一种面向对象的编程语言,它集成于.NET框架中。C#的设计初衷是为了解决当时Sun...

    socket多线程服务器和客户端

    在Java中,我们可以使用`ServerSocket`类来创建监听套接字,并通过`accept()`方法接收连接请求。 多线程的实现通常涉及到`Thread`类或`Runnable`接口。在创建新线程处理客户端连接时,我们会创建一个实现了`...

    swing界面socket多线程聊天室

    综上所述,这个“swing界面socket多线程聊天室”项目涵盖了Java GUI设计、网络编程、多线程技术、文件传输以及用户管理等多个关键领域,是学习和实践这些技能的好例子。通过分析和实现这样的项目,开发者可以深入...

    udp多线程传输例子

    1. **套接字创建**:在C++或Java等编程语言中,首先需要创建一个UDP套接字,这通过调用`socket()`函数完成。套接字可以是服务器端用来接收数据,也可以是客户端用来发送数据。 2. **地址结构设置**:使用`sockaddr_...

    java socket 多线程 断点续传实现

    最近研究了一下socket套接字 实现java多线程 断点续传文件 在网上查找了很多例子 然后学习了大家的方法 最后利用网上的例子 自己整合了一份多线程 断点续传文件的代码 并且能实现客户端发送完毕之后 接收服务器端的...

    线程与socket例子.rar_java_layersnut_socket

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

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

    "多线程Socket阻塞模式下通信的例子.rar"可能包含如何在Java或C#中实现多线程处理Socket通信的代码。 6. **Socket应用实例**: - "socket应用小例程.rar"和"Socket开发资料.rar"可能包含了各种Socket编程的实用...

    java socket 客户端和服务端例子

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

    Java TCP/IP Socket编程

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

    多线程web服务器

    本文将深入探讨多线程Web服务器的核心知识点,包括套接字(Socket)的使用以及TCP程序设计。 首先,我们要理解套接字是网络通信的基础,它是连接客户端和服务器的桥梁。在Java中,`java.net.ServerSocket` 类用于...

    java socket programming example

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

    Java多线程_ServerSocket服务端与客户端通信案例

    Java多线程环境下使用ServerSocket和Socket进行服务端与客户端之间的通信是一个经典的网络编程模型。在这个模型中,服务端使用ServerSocket类监听特定端口,等待客户端的连接请求。而客户端则通过Socket类建立与...

    java_python_socket.zip

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

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

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

    java socket通讯程序源码

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

    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` 实例并指定一个端口号,服务器就会...

    JAVA Socket 网络编程教程

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

    Java socket编程实例代码(Blog配套代码)

    Java套接字(Socket)编程是网络编程的基础,它提供了应用程序之间进行低级通信的端点。在Java中,Socket类代表一个网络连接的端点,而ServerSocket类用于监听客户端的连接请求。本实例代码是为了配合博客文章,提供...

Global site tag (gtag.js) - Google Analytics