- 浏览: 191040 次
- 性别:
- 来自: 厦门
文章分类
最新评论
-
行者买刀:
qxpidt 写道楼主,我想问下,嵌套这些WEB应用后,如何操 ...
JDIC一个能够用java调用ie内核的包 -
qxpidt:
楼主,我想问下,嵌套这些WEB应用后,如何操作你登录的COOK ...
JDIC一个能够用java调用ie内核的包 -
lookforwarding:
...
java重写JSplitPane的UI,设置分隔条的颜色 -
v韧竹v:
最后那个抽象工厂模式,CarType是不是定义错了,应该abs ...
设计模式之略见一斑(工厂模式Factory) -
l7810:
这与模板模式有什么区别啊?
设计模式之略见一斑(建造模式builder)
1.ServerSocket;
ServerSocket有以下3 个选项。
l SO_TIMEOUT:表示等待客户连接的超时时间。
l SO_REUSEADDR:表示是否允许重用服务器所绑定的地址。
l SO_RCVBUF:表示接收数据的缓冲区的大小。
SO_TIMEOUT选项
l 设置该选项:public void setSoTimeout(int timeout) throws SocketException
l 读取该选项:public int getSoTimeout () throws IOException
SO_TIMEOUT 表示ServerSocket 的accept()方法等待客户连接的超时时间,以毫
秒为单位。如果SO_TIMEOUT的值为0,表示永远不会超时,这是SO_TIMEOUT的
默认值。
当服务器执行ServerSocket的accept()方法时,如果连接请求队列为空,服务器就
会一直等待,直到接收到了客户连接才从accept()方法返回。如果设定了超时时间,那
么当服务器等待的时间超过了超时时间,就会抛出SocketTimeoutException,它是
InterruptedException的子类。
example:
import java.io.*; import java.net.*; public class TimeoutTester{ public static void main(String args[])throws IOException{ ServerSocket serverSocket=new ServerSocket(8000); serverSocket.setSoTimeout(6000); //等待客户连接的时间不超过6 秒 Socket socket=serverSocket.accept(); socket.close(); System.out.println("服务器关闭"); } }
运行6秒后会抛出异常:
C:\chapter03\classes>java TimeoutTester
Exception in thread "main" java.net.SocketTimeoutException: Accept timed out
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(Unknown Source)
at java.net.ServerSocket.implAccept(Unknown Source)
at java.net.ServerSocket.accept(Unknown Source)
at TimeoutTester.main(TimeoutTester.java:8)
如果把程序中的“serverSocket.setSoTimeout(6000)”注释掉,那么serverSocket.
accept()方法永远不会超时,它会一直等待下去,直到接收到了客户的连接,才会从
accept()方法返回。
2.ServerSocket 的构造方法
l ServerSocket()throws IOException
l ServerSocket(int port) throws IOException
l ServerSocket(int port, int backlog) throws IOException
l ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException
在以上构造方法中,参数port 指定服务器要绑定的端口(服务器要监听的端口),
参数backlog指定客户连接请求队列的长度,参数bindAddr指定服务器要绑定的IP地址。
import java.net.*; public class Client { public static void main(String args[])throws Exception{ final int length=100; String host="localhost"; int port=8000; Socket[] sockets=new Socket[length]; for(int i=0;i<length;i++){ //试图建立100 次连接 sockets[i]=new Socket(host, port); System.out.println("第"+(i+1)+"次连接成功"); } Thread.sleep(3000); for(int i=0;i<length;i++){ sockets[i].close(); //断开连接 } } } import java.io.*; import java.net.*; public class Server { private int port=8000; private ServerSocket serverSocket; public Server() throws IOException { serverSocket = new ServerSocket(port,3); //连接请求队列的长度为3 System.out.println("服务器启动"); } public void service() { while (true) { Socket socket=null; try { socket = serverSocket.accept(); //从连接请求队列中取出一个连接 System.out.println("New connection accepted " + socket.getInetAddress() + ":" +socket.getPort()); }catch (IOException e) { e.printStackTrace(); }finally { try{ if(socket!=null)socket.close(); }catch (IOException e) {e.printStackTrace();} } } } public static void main(String args[])throws Exception { Server server=new Server(); Thread.sleep(60000*10); //睡眠10 分钟 //server.service(); } }
Client 试图与Server 进行100 次连接。在Server 类中,把连接请求队列的长度设
为3。这意味着当队列中有了3 个连接请求时,如果Client 再请求连接,就会被Server
拒绝
结是如下:
第1 次连接成功
第2 次连接成功
第3 次连接成功
Exception in thread "main" java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(Unknown Source)
at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at Client.main(Client.java:10)
从以上打印结果可以看出,Client 与Server 在成功地建立了3 个连接后,就无法
再创建其余的连接了,因为服务器的队列已经满了。
如果是改为
public static void main(String args[])throws Exception {
Server server=new Server();
//Thread.sleep(60000*10); //睡眠10 分钟
server.service();
}
2.1 设定绑定的IP地址
如果主机只有一个IP 地址,那么默认情况下,服务器程序就与该IP 地址绑定。
ServerSocket的第4 个构造方法ServerSocket(int port, int backlog, InetAddress bindAddr)
有一个bindAddr 参数,它显式指定服务器要绑定的IP地址,该构造方法适用于具有多
个IP地址的主机。假定一个主机有两个网卡,一个网卡用于连接到Internet, IP地址
为222.67.5.94,还有一个网卡用于连接到本地局域网,IP 地址为192.168.3.4。如果服
务器仅仅被本地局域网中的客户访问,那么可以按如下方式创建ServerSocket:
ServerSocket serverSocket=new ServerSocket(8000,10,InetAddress.getByName ("192.168.3.4"));
2.2默认构造方法的作用
ServerSocket有一个不带参数的默认构造方法。通过该方法创建的ServerSocket不
与任何端口绑定,接下来还需要通过bind()方法与特定端口绑定。
这个默认构造方法的用途是,允许服务器在绑定到特定端口之前,先设置
ServerSocket的一些选项。因为一旦服务器与特定端口绑定,有些选项就不能再改变了。
在以下代码中,先把ServerSocket 的SO_REUSEADDR 选项设为true,然后再把
它与8000 端口绑定:
ServerSocket serverSocket=new ServerSocket();
serverSocket.setReuseAddress(true); //设置ServerSocket 的选项
serverSocket.bind(new InetSocketAddress(8000)); //与8000 端口绑定
如果把以上程序代码改为:
ServerSocket serverSocket=new ServerSocket(8000);
serverSocket.setReuseAddress(true); //设置ServerSocket 的选项
那么serverSocket.setReuseAddress(true)方法就不起任何作用了,因为SO_
REUSEADDR选项必须在服务器绑定端口之前设置才有效。
打印结果如下:
第1 次连接成功
第2 次连接成功
第3 次连接成功
…
第100 次连接成功
3. setResuseAddress(boolean b) 的用法
这个选项与Socket的SO_REUSEADDR选项相同,用于决定如果网络上仍然有数
据向旧的ServerSocket传输数据,是否允许新的ServerSocket绑定到与旧的ServerSocket
同样的端口上。SO_REUSEADDR选项的默认值与操作系统有关,在某些操作系统中,
允许重用端口,而在某些操作系统中不允许重用端口。
当ServerSocket 关闭时,如果网络上还有发送到这个ServerSocket 的数据,这个
ServerSocket不会立刻释放本地端口,而是会等待一段时间,确保接收到了网络上发送
过来的延迟数据,然后再释放端口。
许多服务器程序都使用固定的端口。当服务器程序关闭后,有可能它的端口还会
被占用一段时间,如果此时立刻在同一个主机上重启服务器程序,由于端口已经被占
用,使得服务器程序无法绑定到该端口,服务器启动失败,并抛出BindException:
Exception in thread "main" java.net.BindException: Address already in use: JVM_Bind
为了确保一个进程关闭了ServerSocket 后,即使操作系统还没释放端口,同一个
主机上的其他进程还可以立刻重用该端口,可以调用ServerSocket 的setResuse-
Address(true)方法:
if(!serverSocket.getResuseAddress())serverSocket.setResuseAddress(true);
值得注意的是,serverSocket.setResuseAddress(true)方法必须在ServerSocket还没有
绑定到一个本地端口之前调用,否则执行serverSocket.setResuseAddress(true)方法无效。
此外,两个共用同一个端口的进程必须都调用serverSocket.setResuseAddress(true)方法,
才能使得一个进程关闭ServerSocket后,另一个进程的ServerSocket还能够立刻重用相
同端口。
4.SO_RCVBUF选项
SO_RCVBUF表示服务器端的用于接收数据的缓冲区的大小,以字节为单位。一般
说来,传输大的连续的数据块(基于HTTP或FTP协议的数据传输)可以使用较大的缓
冲区,这可以减少传输数据的次数,从而提高传输数据的效率。而对于交互式的通信
(Telnet和网络游戏),则应该采用小的缓冲区,确保能及时把小批量的数据发送给对方。
ServerSocket serverSocket=new ServerSocket();
int size=serverSocket.getReceiveBufferSize();
if(size<131072) serverSocket.setReceiveBufferSize(131072); //把缓冲区的大小设为128K
serverSocket.bind(new InetSocketAddress(8000)); //与8 000 端口绑定
5.创建线程池
l 除了创建和销毁线程的开销之外,活动的线程也消耗系统资源。每个线程本
身都会占用一定的内存(每个线程需要大约1M 内存),如果同时有大量客户
连接服务器,就必须创建大量工作线程,它们消耗了大量内存,可能会导致
系统的内存空间不足。
l 如果线程数目固定,并且每个线程都有很长的生命周期,那么线程切换也是
相对固定的。不同操作系统有不同的切换周期,一般在20 毫秒左右。这里所
说的线程切换是指在Java 虚拟机,以及底层操作系统的调度下,线程之间转
让CPU的使用权。如果频繁创建和销毁线程,那么将导致频繁地切换线程,
因为一个线程被销毁后,必然要把CPU转让给另一个已经就绪的线程,使该
线程获得运行机会。在这种情况下,线程之间的切换不再遵循系统的固定切
换周期,切换线程的开销甚至比创建及销毁线程的开销还大。
采用线程池:预先创建了一些工作线程,它们不断从工作队列中取出任务,然后执行该任务。当工
作线程执行完一个任务时,就会继续执行工作队列中的下一个任务。线程池具有以下
优点:
l 减少了创建和销毁线程的次数,每个工作线程都可以一直被重用,能执行多
个任务。
l 可以根据系统的承载能力,方便地调整线程池中线程的数目,防止因为消耗
过量系统资源而导致系统崩溃。
package multithread2; import java.util.LinkedList; public class ThreadPool extends ThreadGroup { private boolean isClosed=false; //线程池是否关闭 private LinkedList<Runnable> workQueue; //表示工作队列 private static int threadPoolID; //表示线程池ID private int threadID; //表示工作线程ID public ThreadPool(int poolSize) { //poolSize 指定线程池中的工作线程数目 super("ThreadPool-" + (threadPoolID++)); setDaemon(true); workQueue = new LinkedList<Runnable>(); //创建工作队列 for (int i=0; i<poolSize; i++) new WorkThread().start(); //创建并启动工作线程 } /** 向工作队列中加入一个新任务,由工作线程去执行该任务 */ public synchronized void execute(Runnable task) { if (isClosed) { //线程池被关则抛出IllegalStateException异常 throw new IllegalStateException(); } if (task != null) { workQueue.add(task); notify(); //唤醒正在getTask()方法中等待任务的工作线程 } } /** 从工作队列中取出一个任务,工作线程会调用此方法 */ protected synchronized Runnable getTask()throws InterruptedException{ while (workQueue.size() == 0) { if (isClosed) return null; wait(); //如果工作队列中没有任务,就等待任务 } return workQueue.removeFirst(); } /** 关闭线程池 */ public synchronized void close() { if (!isClosed) { isClosed = true; workQueue.clear(); //清空工作队列 interrupt(); //中断所有的工作线程,该方法继承自ThreadGroup类 } } /** 等待工作线程把所有任务执行完 */ public void join() { synchronized (this) { isClosed = true; notifyAll(); //唤醒还在getTask()方法中等待任务的工作线程 } Thread[] threads = new Thread[activeCount()]; //enumerate()方法继承自ThreadGroup类,获得线程组中当前所有活着的工作线程 int count = enumerate(threads); for (int i=0; i<count; i++) { //等待所有工作线程运行结束 try { threads[i].join(); //等待工作线程运行结束 }catch(InterruptedException ex) { } } } /** 内部类:工作线程 */ private class WorkThread extends Thread { public WorkThread() { //加入到当前ThreadPool 线程组中 super(ThreadPool.this,"WorkThread-" + (threadID++)); } public void run() { while (!isInterrupted()) { //isInterrupted()方法继承自Thread 类,判断线程是否被中断 Runnable task = null; try { //取出任务 task = getTask(); }catch (InterruptedException ex){} // 如果getTask()返回null 或者线程执行getTask()时被中断,则结束此线程 if (task == null) return; try { //运行任务,异常在catch代码块中捕获 task.run(); } catch (Throwable t) { t.printStackTrace(); } } //#while } //#run() } //#WorkThread 类 }
在ThreadPool类中定义了一个LinkedList类型的workQueue成员变量,它表示工
作队列,用来存放线程池要执行的任务,每个任务都是Runnable实例。ThreadPool 类
的客户程序(利用ThreadPool 来执行任务的程序)只要调用ThreadPool 类的execute
(Runnable task)方法,就能向线程池提交任务。在ThreadPool类的execute()方法中,先
判断线程池是否已经关闭。如果线程池已经关闭,就不再接收任务,否则就把任务加
入到工作队列中,并且唤醒正在等待任务的工作线程。
在ThreadPool 类的构造方法中,会创建并启动若干工作线程,工作线程的数目由
构造方法的参数poolSize决定。WorkThread类表示工作线程,它是ThreadPool类的内
部类。工作线程从工作队列中取出一个任务,接着执行该任务,然后再从工作队列中
取出下一个任务并执行它,如此反复。
工作线程从工作队列中取任务的操作是由ThreadPool 类的getTask()方法实现的,
它的处理逻辑如下:
l 如果队列为空并且线程池已关闭,那就返回null,表示已经没有任务可以执
行了;
l 如果队列为空并且线程池没有关闭,那就在此等待,直到其他线程将其唤醒
或者中断;
l 如果队列中有任务,就取出第一个任务并将其返回。
线程池的join()和close()方法都可用来关闭线程池。join()方法确保在关闭线程池之
前,工作线程把队列中的所有任务都执行完。而close()方法则立即清空队列,并且中
断所有的工作线程。
ThreadPool 类是ThreadGroup类的子类。ThreadGroup 类表示线程组,它提供了一
些管理线程组中线程的方法。例如,interrupt()方法相当于调用线程组中所有活着的线
程的interrupt()方法。线程池中的所有工作线程都加入到当前ThreadPool 对象表示的线
程组中。ThreadPool类在close()方法中调用了interrupt()方法:
/** 关闭线程池 */
public synchronized void close() {
if (!isClosed) {
isClosed = true;
workQueue.clear(); //清空工作队列
interrupt(); //中断所有的工作线程,该方法继承自ThreadGroup类
}
}
以上interrupt()方法用于中断所有的工作线程。interrupt()方法会对工作线程造成以
下影响:
l 如果此时一个工作线程正在ThreadPool 的getTask()方法中因为执行wait()方
法而阻塞,则会抛出InterruptedException;
l 如果此时一个工作线程正在执行一个任务,并且这个任务不会被阻塞,那么
这个工作线程会正常执行完任务,但是在执行下一轮while (!isInterrupted())
{…}循环时,由于isInterrupted()方法返回true,因此退出while循环。
如例程3-7所示,ThreadPoolTester 类用于测试ThreadPool的用法。
评论
不过有个问题想请教博主
我想发送Http GET请求,使用了socket,请问有没有办法能够使用同一个socket进行多次请求呢?
因为不想每发一次请求就进行一次连接,不知是否有可能,我对HTTP协议不是很了解。请博主指教。
发表评论
-
UtilCommon
2016-08-16 07:23 0aaaaaa -
Java面试题全集(上)
2016-08-14 17:23 0版权声明:本文为博 ... -
设计模式之略见一斑(Visitor访问者模式)
2010-02-25 15:02 3189在开发中,我们可能会经常碰到客户提了一新的需求,那么在现 ... -
设计模式之略见一斑(Mediator中介者模式)
2010-02-25 10:07 1840设计模式 写道 通常,面向对象的软件开发要求尽可能 ... -
设计模式之略见一斑(Chain of Responsibility责任链模式)
2010-02-24 15:00 1460设计模式 写道 面向对 ... -
设计模式之略见一斑(Observer观察者模式)
2010-02-23 17:15 2173用户通常通过调用对象的方法来收集该对象的信息。但是当这 ... -
设计模式之略见一斑(Memento备忘录模式)
2010-02-23 11:46 1431有时候,我们需要 ... -
设计模式之略见一斑(Template Method模板方法模式)
2010-02-22 21:33 1408模板方法模式就是预 ... -
设计模式之略见一斑(策略模式strategy)
2010-02-22 17:56 1932java设计模式 写道 ... -
设计模式之略见一斑(状态模式State)
2010-02-22 15:42 1646设计模式中的状态模式相对比较简单,简单的说就是对某 ... -
设计模式之略见一斑(解释器模式Interpreter)
2010-02-22 10:27 3326解释器模式是 ... -
设计模式之略见一斑(命令模式Command)
2010-02-22 09:49 1516终于把构造模式的几种设计模式写完,接下来开始写的行为模 ... -
设计模式之略见一斑(享元模式flyweight)
2010-02-10 11:39 1401flyweight模式中文解释为轻量极模式,所以顾名 ... -
设计模式之略见一斑(代理模式Proxy)
2010-02-10 11:04 1914普通对象所需要完成的任务就是通过公共接口为外界提供自己所承诺的 ... -
设计模式之略见一斑(装饰模式decorator)
2010-02-09 11:08 1776标头:(引自设计模式 ... -
设计模式之略见一斑(组合模式Composite)
2010-02-08 14:45 1466定义: 将对象以树形结构组织起来,以达成"部 ... -
设计模式之略见一斑(外观模式Facade)
2010-02-07 09:30 1347外观模式又称门面模式,它是为了给子系统中提供一个一致的界面,从 ... -
设计模式之略见一斑(桥梁模式bridge)
2010-02-06 18:04 1516桥梁模式的宗旨就是将 ... -
设计模式之略见一斑(适配器模式Adapter)
2010-02-03 10:39 1568适配器模式就是基于客户提供的接口和功能,再此基础上实 ... -
设计模式之略见一斑(原型模式Prototype)
2010-02-01 17:15 1652原型模式允许一个对象 ...
相关推荐
Java语言Socket接口用法详解.doc Java语言Socket接口用法详解.doc Java语言Socket接口用法详解.doc Java语言Socket接口用法详解.doc Java语言Socket接口用法详解.doc Java语言Socket接口用法详解.doc Java语言Socket...
所以我对socket进行了封装,客户端和服务端可以通过配置注解,让双方相互调用注解方法,提供了专门的工具类,让注解方法可以支持返回list或map等集合或其他的类型,三行代码你就可以完美的使用socket进行通信,支持...
通过socket客户/服务器编程可以创建一个能被许多人使用的分布式程序,并且所有客户均可以用统一的前端进行工作,并与服务器进行通信。 要想与服务器通信必须具备三个条件:服务器程序、客户程序和连接它们的...
java socket用法 含有java示例
近正在做一个项目,其中遇到了一个问题是java与.NET之间的通信问题。具体的问题是这样的: 客户端使用java,服务器端使用的是C#。两者之间使用基于TCP的Socket通信方式。可是,做了一个测试小例子,结果从客户端...
使用socket实现的简单聊天室功能,包含客户端和服务器端代码,可以通过本实例快速了解java中socket的使用方法
java c++ socket java c++ socket java c++ socket java c++ socket java c++ socket java c++ socket java c++ socket java c++ socket java c++ socket java c++ socket java c++ socket
封闭式Java Socket代码,提供TCP UDP 阻塞和非阻塞的方法,无需知道具体实现方式,只需要Main.java(Server)Main2.java(Client)Main(UDP)三个例程,简单建立联接。SocketIO接口提供精简化的方法,一体化输入输出,...
简单的java socket源码,使用方法同我的另一个RMI实例的资源说明
java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,其它方法大家可以见JDK-1.3文档。 . Accept方法用于产生"阻塞",直到接受到一个连接,并且返回一个客户端...
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的...Socket通常常使用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个port号唯一确定。
NULL 博文链接:https://410063005.iteye.com/blog/1751243
Socket的dll文件,采用的是非常新的HP-Socket版本,demo是整套java工程,导入eclipse修改HpSocket.java文件中的服务器的IP和端口就可以测试,里面还包含了客户端接收服务器端返回的信息方法,看懂了客户端基本也可以...
【资源说明】 基于java实现Socket套接字一对一聊天系统源码+项目说明.zip... // 方法一: socket.close(); // 方法二: // 给服务器发送相关消息,由服务器断开与指定客户端的连接 【备注】更多详情介绍见项目说明!
这本PDF书主要说java的 Socket的原理和用法
该项目是一个基于WebSocket和Java Socket的交互型BS平台,提供聊天、直播、模拟面试和弹幕互动功能。用户可以进行点对点聊天、群聊...建议先了解WebSocket和Java Socket的基本概念和使用方法,然后比对项目代码进行理解
基于Socket的java网络编程, Socket通讯的过程 Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server...
现在几乎所有互联网应用程序都使用Java Socket进行通信,而本书专注的、教导式的方法,使读者能够快速掌握所有计算机通信的任务和技术要点。 本书特点: 对Socket编程的重点进行了集中简明的介绍,以使读者能够迅速...
Java中的网络通信时通过Socket实现的,Socket分为ServerSocket和Socket两大类,ServerSocket用于服务器端,可以通过accept方法监听请求,监听请求后返回Socket,Socket用于完成具体数据传输,客户端也可以使用...
在7CP/IP Socket首次发布时,Java作为一个新的未被关注的编程语 言刚出现。然而,自2001年以来,Java的网络编程能力已经得到了很大程度的扩展,而且 持续的应用优势已经使其成为了一个占主导地位的平台。考虑到Java...