• java网络编程socket解析


    转载:http://www.blogjava.net/landon/archive/2013/07/02/401137.html

    Java网络编程精解笔记2:Socket详解

    Socket用法详解
    在C/S通信模式中,client需要主动创建于server连接的Socket(套接字).服务器端收到了客户端的连接请求,也会创建与客户连接的Socket.Socket可看做是通信两端的收发器.server与client都通过Socket来收发数据.

    1.构造Socket

    1.Socket()
    2.Socket(InetAddress address,int port) throws UnknownHostException,IOException
    3.Socket(InetAddress addrss,int port,InetAddress localAddr,int localPort) throws IOException
    4.Socket(String host,int port) throws UnknownHostException,IOException
    5.Socket(String host,int port,InetAddress localAddr,int localPort) throws IOExcception

    除了第一个不带参数的构造方法外,其他构造方法都会试图建立与服务器的连接.如果连接成功,就返回Socket对象.如果因为某些原因连接失败,则抛出IOException.

    2.设定等待建立连接的超时时间

    1.客户端的Socket构造方法请求与server连接时,可能要等待一段时间.默认会一直等待下去,直到连接成功或者出现异常.Socket构造方法请求连接时,受底层网络传输速度的影响,可能处于长时间的等待状态.
    ->希望限定等待连接的时间
    ->Socket socket = new Socket();
    SocketAddress rermoteAddr = new InetSocketAddress("localhost",8000);
    socket.connect(remoteAddr,60000);//设置等待建立连接的超时时间为1分钟
    ->如果1分钟之内连接成功,则connect顺利返回.如果1分钟之内出现异常,则抛出该异常.如果超过了1分钟,即没有连接成功,也没有出现其他异常.则会抛出
    SocketTimeoutException

    2.Socket#connect(SocketAddress endpoint,int timeout).endpoint为服务器的地址,timeout设定超时时间.ms->
    timeout为0,表示永远不会超时.

    3.设定服务器的地址.

    Socket(InetAddress address,int port)
    Socket(String host,int port)
    InetAddress表示服务器的IP地址.->该类提供了一系列的静态工厂方法.用于构造自身的实例.如
    1.InetAdress addr1 = InetAdress.getLocalHost();
    2.InetAddress addr2 = InetAddress.getByName("10.10.137.44");
    3.InetAddress addr2 = InetAddress.getByName("www.javathinker.org");

    4.设定客户端的地址
    1.在一个Socket对象中,即包含远程服务器的IP和端口信息,也包含本地客户端的IP地址和端口信息.默认情况下,客户端的IP地址来自客户程序所在的主机,而客户端的端口则有操作系统随机分配.
    ->Socket(InetAddress address,int port,InetAddress localAddress,int localPort) throws IOException
    ->Socket(String host,int port,InetAddress localAddress,int localPort) throws IOException
    上两个方法用来设置客户端的ip端口和地址
    ->这种情况主要适用于一个主机同时属于两个以上的网络,它可能拥有两个以上的IP地址.如一个在Internet,一个在局域网.
    ->如果希望和局域网的服务器程序通讯,则可以以局域网的IP地址作为localAddress来构造Socket.

    5.客户连接服务器时可能抛出的异常

    1.UnknownHostException:无法识别主机的名字或ip地址时,就会抛出此异常
    2.ConnectException:如果没有服务器监听指定的端口;或者服务器进程拒接连接,则会抛出此异常.
    3.SocketTimeoutException:如果等待连接超时,就会抛出此异常.
    4.BindException:如无法把Socket对象与指定的本地IP地址或端口绑定则会抛出此异常.

    IOException
    -UnknownHostException
    -InterruptedIOException
    -SocketTimeoutException
    -SocketException
    -BindException
    -ConnectException

    6.获取Socket的信息

    1.同时包含了远程服务器的IP和端口信息以及客户本地的IP和端口信息.
    2.获取输出流合输入流,分别用于向服务器发送数据以及接收从服务端发来的数据.

    1.getInetAddress():获得远程服务器的IP地址
    2.getPort():获得远程服务器的端口
    3.getLocalAddress():获得客户本地的IP地址
    4.getLocalPort():获得客户本地的端口
    5.getInputStream():获得输入流.如果Sokcet还没有连接或已经关闭或者已经通过shutdownInput方法关闭输入流,则才方法会抛出IOException.
    6.getOutputStream(): 获得输入流..如果Sokcet还没有连接或已经关闭或者已经通过shutdownOutput方法关闭输出流,则才方法会抛出IOException.

    7.关闭Socket

    1.当client与Server通信结束,应该及时关闭Socktt,以释放Socket占用的包括端口在内的各种资源.
    2.Socket#close方法负责关闭socket.当一个Socket对象被关闭就不能通过其输入和输出流进行io操作.否则会导致IOException.
    3.确保关闭Socket的操作就是被执行,建议把该操作放在finally代码块中.如
    Socket socket = null;
    try
    {
    socket = new Socket("www.thinker.org",80);
    //执行接收和发送数据的操作
    ...
    }
    catch(IOException e)
    {
    e.printStackTrace();
    }
    finally
    {
    try
    {
    if(socket != null)
    {
    socket.close();
    }
    catch(IOException e)
    {
    e.printStackTrace();
    }
    }
    }

    4.Socket类提供了3个状态测试方法.
    1.isClosed()
    1.public synchronized void close() throws IOException {
    synchronized(closeLock) {
    if (isClosed())
    return;
    if (created)
    impl.close();
    closed = true;
    }
    }
    2.public boolean isClosed() {
    synchronized(closeLock) {
    return closed;// true if the socket has been closed
    }
    }

    2.isConnected()
    1.true if the socket was successfuly connected to a server
    2. Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket
    (see {@link #isClosed()}) if it was successfuly connected prior to being closed.
    3.isBound()
    1. true if the socket was successfuly bound to an address
    2.Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket
    (see {@link #isClosed()}) if it was successfuly bound prior to being closed.

    4.判断一个Socket对象是否处于连接状态,用以下形式:
    boolean isConnected = socket.isConnected() && !socket.isClosed()

    8.半关闭Socket

    A进程与B进程通过Socket通信.假定A输出数据,B读入数据.A如何告诉B所有数据已经输出完毕:
    1.A与B交换的是字符流,且一行一行的读写.可事先约定以一个特殊标志作为结束标志,如以"bye"作为结束标志.当A向B发送一行字符串"bye"时,B读到这一行数据时,则停止读数据.{@link EchoServer},{@link EchoClient}
    2.进程A先发送消息,告诉B所发送正文的长度.->再发送正文.->B先获知A发送的正文长度->接下来只要读取完该长度的字符或者字节,就停止读数据.
    3.A发完所有数据后,关闭Socket->B读取A发送的所有数据后->InputStream#read->该方法返回-1.->BufferedReader#readLine->返回null.
    {@link HTTPClient}
    4.Socket#close->输入输出流都被关闭->有时候希望仅关闭输入流或输出流之一->Socket半关闭方法->
    shutdownInput():关闭输入流
    shutdownOutput():关闭输出流
    ->B读取数据时,如果A的输出流已经关闭->B读入所有数据后,就会读到输入流的末尾.
    ->先后调用Socket的shutdonwInput和shutdownOutput方法.仅仅是关闭了输入流和输出流,并不等价Socket#close.->通信结束后,依然要调用Socket的close方法.只有该方法才会释放Socket占用的资源.如占用的本能地端口等.
    5.Socket#isInputShutdown()->输入流关闭,返回true.
    Socket#isOutputShutdown()->输出流关闭,返回true
    6.client与Server通信时,如果有一方突然结束程序或者关闭了Socket或者单独关闭了输入流或输出流.对另一方会造成什么影响.
    {@link Sender} {@link Receiver}.

    9.设置Socket选项

    1.TCP_NODELAY:表示立即发送数据

    1.public void setTcpNoDelay(boolean on) throws SocketException
    2.public boolean getTcpNoDelay() throws SocketException
    3.默认情况,发送数据采用Negale算法.即指发送方发送的数据不会立即发出,而是先放到缓冲区内.等缓冲区区慢了再发出.->发送完一批数据等待接收方对这批数据的回应.->再发送下一批数据.->适用于发送方需要发送大批量数据,且接收方会及时回应的场合->通过减少传输数据的次数来提高通信效率.
    ->对于发送方持续发送小批量数据,且接收方不一定立即发送响应->该算法会使发送方运行很慢->如实时网络游戏
    4.TCP_NODELAY默认值为false->即表示采用Negale算法.->setTcpNoDelay(true)->关闭Socket缓存,确保数据及时发送
    5.if(!socket.getTcpNoDelay()){socket.setTcpNoDelay(true)}
    6.Socket底层不支持该选项,则抛出SocketException.

    2.SO_REUSEADDR:表示是否允许重用Socket所绑定的本地地址

    1.public void setReuseAddress(boolen on) throws SocketException
    2.public boolean getReuseAddress() throws SocketException
    3.接收方通过Socket#close关闭Socket->如果网络上还有发送到这个Socket的数据,那么底层的Socket不会立刻释放本地端口->会等待一段时间->确保接收到了网络上发送过来的延迟数据->释放端口->Socket收到延迟数据后,不会对这些数据做任何处理->Socket接收延迟数据的目的->确保这些数据不会被其他恰巧绑定到同样端口的新进程接收到.
    4.客户端程序一般采用随机端口->出现两个client程序绑定到同样端口的可能性不大
    5.server程序采用固定端口->server关闭后,其端口可能还会被占用一段时间->此时如果重启程序,端口已经被占用->使得程序无法绑定到给端口->启动失败
    6.确保一个进程关闭Socket后,即使其还未释放端口->同一个主机上的其他进程还可以立即重用该端口->
    if(!socket.getReuseAddress()){socket.setReuseAddress(true)}
    7.该方法必须在Socket还未绑定到一个本地端口之前调用.否则无效.
    1.Socket socket = new Socket();
    socket.setResueAddress(true);
    socket.connect(new InetSocketAddress("localhost",8080));
    2.Socket socket = new Socket();
    socket.setResueAddress(true);
    socket.bind(new InetSocketAddress("localhost",9000));
    socket.connect(new InetSocketAddress("remotehost",8000));
    8.两个公用一个端口的进程必须都调用socket.SetResueAddress(true)->才能使得一个进程关闭Socket后,另一个进程的Socket能立即重用相同端口.
    9.当多个ServerSocket对象同时绑定一个端口时,系统会随机选择一个ServerSocket对象来接收客户端请求->接收客户端请求的ServerSocket对象必须关闭才能轮到其他的ServerSocket对象接收客户端请求。如果不关闭这个ServerSocket对象,那么其他的ServerSocket对象将永远无法接收客户端请求

    3.SO_TIMEOUT:表示接收数据时的等待时间

    1.public void setSoTimeout(int milliseconds) throws SocketException
    2.public int getSoTimeout() throws SocketException
    3.通过Socket的输入流读数据时,如果还未有数据,则等待:
    如:
    byte[] buff = new byte[1024];
    InputStream in = socket.getInputStream();
    in.read(buff);
    ->输入流没有数据,则in.read(buff)就会等待发送方发送数据->结束等待条件:
    1.输入流中有1024个字节->read将其读到buff中->返回读到的字节数
    2.距离输入流末尾还有小雨1024个字节->read读到buff中,返回读到的字节数
    3.读到输入流的末尾
    4.连接已经断开,抛出IOException
    5.Socket#setSoTimeout设置了等待超时时间,超过这一时间则抛出SocketTimeoutException
    4.该选项用于设定接收数据的等待超时时间,单位为毫秒->默认值为0,表示无限等待,永远不会超时.
    5.该方法必须在接收数据之前执行才有效.
    6.输入流的read方法抛出SocketTimeoutException后,Socket依然是连接的->可尝试再次读取数据->
    socket.setTimeout(3 * 60 * 1000);
    byte[] buff = new byte[1024];
    InputStream in = socket.getInputStream();

    int len = -1;

    do
    {
    try
    {
    len = in.read(buff);
    // 处理读到的数据
    ...
    }
    catch(SocketTimeoutException e)
    {
    e.printStackTrace();
    len = 0;
    }
    }
    while(len != -1)

    4.SO_LINGER:表示当执行Socket的close方法时,是否立即关闭底层Socket

    1.public void setSoLinger(boolean on,int seconds) throws SocketException
    2.public int getSoLinger() throws SocketException
    3.该选项用来控制Socket关闭时的行为->默认执行Socket的close,该方法会立即返回.但是底层的Socket不立即关闭,会延迟一段时间,知道发送完所有剩余的数据->真正关闭socket->断开连接.
    4.socket.setSoLinger(true,0)->执行Socket#close时,该方法立即返回且底层的Socket也会立即关闭->所有未发送完的剩余数据被丢弃.
    5.socket.setSoLinger(true,60)->
    1.Socket#close->该方法不会立即返回->进入阻塞状态
    2.底层的Socket会尝试发送剩余的数据->返回条件:
    1.底层的Socket已经发送完所有剩余数据
    2.尽管底层的Socket还没有发送完所有的剩余数据->但是已经阻塞了60秒->也会返回->剩余未发送的数据将被丢弃
    1.->close返回后->底层的Socket会被关闭,断开连接
    2.setSoLinger(boolean on,int seconds)->seconds参数以秒为单位->
    6.程序通过输出流写数据时,->仅表示程序向网络提交了一批数据->由网络负责输送到到接收方->程序关闭Socket时,有可能这批数据还在网络上传输,未达到接收方->未发送完的数据指还在网络上传输未被接收方接收的数据
    {@link TestLingerClient} {@link TestLingerServer}

    5.SO_SNDBUF:表示发送数据的缓冲区大小
    1.public void setSendBufferSize(int size) throws SocketException
    2.public int getSendBufferSize() throws SocketException
    3.该选项用来表示Socket用于输出数据的缓冲区的大小->底层Socket不支持该选项->set 抛出SocketException

    6.SO_RCVBUF:表示接收数据的缓冲区大小
    1.public void setReceiveBufferSize(int size) throws SocketException
    2.public int getReceiveBufferSize() throws SocketException
    3.该选项用来表示Socket的用于输入数据的缓冲区的大小->传输大的连续的数据块,如基于HTTP和FTP协议的通信,可以使用较大缓冲区->减少数据传输的次数->提高传输数据的效率->对于交互频繁且单次传送数据量比较小的通信方式如Telnet和网络游戏,则应该采用交换缓冲区.确保小批量的数据能及时发送给对方.-->设定缓冲区大小的原则使用与SO_SNDBUf选项
    4.底层Socket不支持该选项->set 抛出SocketException.


    7.SO_KEEPALIVE:表示对于长时间处于空闲状态的Socket,是否要自动把它关闭.

    1.public void setKeepAlive(boolean on) throws SocketException
    2.public boolean getKeepAlive() throws SocketException
    3.该选项为true->底层的TCP实现会监视该连接是否有效->当连接处于空闲状态(连接的两端没有互相传送数据)->超过2小时->本地的TCP实现会发送一个数据包一个远程的Socket->远程Socket没有发回响应->TCP实现持续尝试11分钟->直到接收到响应->12分钟内未收到响应->TCP实现就会自动关闭本地Socket,断开连接->不同的网络平台,TCP实现尝试与远程Socket对话的实现会有所差别.
    4.该选项为false->表示TCP不会监视连是否有效->不活动的client可能会永久存在下去->而不会注意server已经崩溃
    5.if(!socket.getKeepAlive()){socket.setKeepAlive(true)}

    8.OOBINLINE:表示是否支持发送一个字节的TCP紧急数据
    //注OOB:out-of-band 带外
    1.public void setOOBInline(boolean on) throws SocketException
    2.public int getOOBInline() throws SocketException
    3.该选项为true,表示支持发送一个自己的TCP紧急数据->Socket#sendUrgentData(int data),用于发送一个字节的TCP紧急数据
    4.该选项为false->接收方收到紧急数据时不做处理,直接丢弃->需要socket.setOOBInline(true)->接收方会将接收到的紧急数据与普通数据放在同样的队列->注:除非采用更高层次的协议,否则接收方处理紧急数据的能力非常有限->紧急数据到来时,接收方不会得到任何通知->因此很难区分普通数据与紧急数据->只好按照同样的方式处理.


    10.服务类型选项

    1.用户去邮局时,可选择不同的服务->发送普通信 | 挂号信 | 快件->价格,发送速度及可靠性均不同.
    2.Internet上传输数据也分为不同的服务器类型.->如发送视频需要较高的宽带,快速到达目的,保证接收方看到连续的画面.
    3.IP规定了4种服务类型,定性的描述服务的质量:
    1.低成本->发送成本低.
    2.高可靠性->保证把数据可靠的送达目的地.
    3.最高吞吐量->一次性可以接收或发送大批量的数据
    4.最小延迟->传输数据的速度要快,把数据快速送达目的地.
    4.4种服务类型可以组合->即可进行或运算
    IPTOS_LOWCOST (0x02)
    IPTOS_RELIABILITY (0x04)
    IPTOS_THROUGHPUT (0x08)
    IPTOS_LOWDELAY (0x10)
    {@link Socket#setTrafficClass}
    5.public void setTrafficClass(int trafficClass) throws SocketException
    public int getTrafficClass() throws SocketException

    11.设置连接时间,延迟和带宽的相对重要性(注意相对二字)
    1.Socket#setPerformancePreferences(int connectionTime,int latency,int bandwidth)
    2.3个参数为网络传输数据的3项指标
    1.connectionTime-表示用最少时间建立连接
    2.latency-表示最小延迟
    3.bandwidth-表示最高带宽
    ->三项指标的相对重要性.->3项参数的整数之前的相对大小决定了响应参数的相对重要性.
    如setPerformancePreferences(2,1,3)->则表示最高带宽最重要,其实是最少连接时间,最后是最小延迟.

    12.小结:
    1.通信过程中,如果发送方没有关闭Socket,就突然中止程序,则接收方在接收数据时会抛出SocketException.
    2.发送方发送完数据后,应该及时关闭Socket或关闭Socket的输出流,这样,接收方就能顺利读到输入流的末尾.

    部分源代码:

    package com.game.landon.socket;

    import java.io.IOException;
    import java.net.BindException;
    import java.net.ConnectException;
    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.net.SocketAddress;
    import java.net.SocketTimeoutException;
    import java.net.UnknownHostException;

    /**
    *
    *测试Socket连接服务器可能抛出的异常
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2012-10-9
    *
    */

    public class ConnectTester
    {
    public static void main(String[] args)
    {
    //默认的host+port
    String host = "localhost";
    int port = 8000;

    //通过main参数解析host+port
    if(args.length > 1)
    {
    host = args[0];
    port = Integer.parseInt(args[1]);
    }

    new ConnectTester().connect(host, port);
    }

    public void connect(String host,int port)
    {
    SocketAddress remoteAddress = new InetSocketAddress(host,port);
    Socket socket = null;
    String result = "";

    try
    {
    long begin = System.currentTimeMillis();
    socket = new Socket();//这里未指定任何参数
    // socket.connect(remoteAddress,5000);//设置超时时间为5秒
    socket.connect(remoteAddress,100);//超时时间设短,用来测试SocketTimeoutException
    long end = System.currentTimeMillis();
    result = (end - begin) + "ms";//计算连接所化的时间
    }
    catch(BindException e)//绑定异常
    {
    result = "Local address and port can't be binded";
    //1.调用Socket#bind方法绑定本地IP|端口
    //2.Socket构造方法中指定本地IP|端口
    //->如果本地主机不具有IP地址或者端口已经被占用,则会抛出此异常
    }
    catch(UnknownHostException e)//无法识别主机server的ip地址
    {
    result = "Unknown host";//测试参数 unknownhost 80
    }
    catch(ConnectException e)//如果没有服务器进程监听指定的端口,或者服务器进程拒绝连接,就会抛出这种异常
    {
    result = "Connection refused";//测试参数1: localhost 7777(没有服务器进程监听7777端口) 测试2:server指定连接请求队列的长度
    }
    catch(SocketTimeoutException e)//服务器超时就会抛出此异常
    {
    result = "Timeout";// 测试参数 www.javathinker.org 80
    }
    catch(IOException e)
    {
    result = "failure";
    }
    finally
    {
    try
    {
    if(socket != null)
    {
    socket.close();
    }
    }
    catch(IOException e)
    {
    e.printStackTrace();
    }
    }

    //打印结果
    System.out.println(remoteAddress + " : " + result );
    }
    }

    package com.game.landon.socket;

    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.net.SocketAddress;
    import java.net.SocketTimeoutException;

    /**
    *
    *Socket连接超时
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2013-6-9
    *
    */

    public class ConnectTimeout
    {
    public static void main(String[] args)
    {
    try
    {
    Socket socket = new Socket();
    SocketAddress serverAddr = new InetSocketAddress("localhost", 8000);

    socket.connect(serverAddr, 60 * 1000);//指定1分钟超时时间
    }
    catch(SocketTimeoutException timeoutException)
    {
    System.out.println("connect localhost:8000 timeout in 1minutes:" + timeoutException);
    }
    catch(IOException ioException)
    {
    System.out.println("connect localhost:8000 fail:" + ioException);
    }
    }
    }

    package com.game.landon.socket;

    import java.io.BufferedReader;
    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.Socket;

    /**
    *
    *测试连接到一个http服务器,然后发送http协议的请求,接着接收从http服务器发回的响应结果
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2012-10-9
    *
    */

    public class HTTPClient
    {
    String host = "www.javathinker.org";
    int port = 80;
    Socket socket;

    public void createSocket() throws Exception
    {
    socket = new Socket(host,port);
    }

    //访问网页www.javathinker.org/index.jsp
    public void communication() throws Exception
    {
    //组装http请求协议
    StringBuffer sb = new StringBuffer("GET " + "/index.jsp" + " HTTP/1.1 ");
    sb.append("Host:www.javathinker.org ");
    sb.append("Accept:*/* ");
    sb.append("Accept-Language:zh-cn ");
    sb.append("Accept-Encoding:gzip,deflate ");
    sb.append("User-Agent:Mozilla/4.0(compatible;MSIE 6.0;Window NT 5.0) ");
    sb.append("Connection:Keep-Alive ");

    //发出http请求->request
    OutputStream socketOut = socket.getOutputStream();
    // 发送数据时,先把字符串形式的请求信息转换为字节数组,即字符串的编码 sb.toString().getBytes()
    socketOut.write(sb.toString().getBytes());
    socket.shutdownOutput();//关闭输出流

    //接收响应结果->response
    InputStream socketIn = socket.getInputStream();
    // 接收数据时把接收到的字节写到一个ByteArrayOutputSteam中,其是一个容量能够自动增长的缓冲区.
    //socketIn.read(buff)返回-1,则表示独到了输入流的末尾
    // 问题,如果接收的网页数据量很大,则先把这些数据全部保存在ByteArrayOutputSteam,很不明智,因为这些数据会占用大量内存.->
    //更有效的做法是利用BufferReader来逐行读取数据
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    byte[] buff = new byte[1024];
    int len = -1;

    while((len = socketIn.read(buff)) != -1)
    {
    //将buff写入buffer
    buffer.write(buff, 0, len);
    }

    System.out.println(new String(buffer.toByteArray()));//把字节数组转为字符串
    socket.close();
    }

    //利用BufferReader逐行读取数据
    public void communication2() throws Exception
    {
    //组装http请求协议
    StringBuffer sb = new StringBuffer("GET " + "/index.jsp" + " HTTP/1.1 ");
    sb.append("Host:www.javathinker.org ");
    sb.append("Accept:*/* ");
    sb.append("Accept-Language:zh-cn ");
    sb.append("Accept-Encoding:gzip,deflate ");
    sb.append("User-Agent:Mozilla/4.0(compatible;MSIE 6.0;Window NT 5.0) ");
    sb.append("Connection:Keep-Alive ");

    //发出http请求->request
    OutputStream socketOut = socket.getOutputStream();
    // 发送数据时,先把字符串形式的请求信息转换为字节数组,即字符串的编码 sb.toString().getBytes()
    socketOut.write(sb.toString().getBytes());
    socket.shutdownOutput();//关闭输出流

    //接收响应结果->response
    InputStream socketIn = socket.getInputStream();
    // 问题,如果接收的网页数据量很大,则先把这些数据全部保存在ByteArrayOutputSteam,很不明智,因为这些数据会占用大量内存.->
    //更有效的做法是利用BufferReader来逐行读取数据

    BufferedReader br = new BufferedReader(new InputStreamReader(socketIn));
    String data;

    while((data = br.readLine()) != null)
    {
    System.out.println(data);
    }

    socket.close();
    }

    public static void main(Stringargs) throws Exception
    {
    HTTPClient client = new HTTPClient();
    client.createSocket();
    // client.communication();
    client.communication2();
    }
    }

    package com.game.landon.socket;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.InetAddress;
    import java.net.Socket;

    /**
    *
    *发送邮件的SMTP客户程序
    *
    *<pre>
    *1.SMTP-Simple Mail Transfer Protocol,简单邮件传输协议,应用层协议,建立在TCP/IP协议基础之上.
    *2.RFC821
    *3.SMTP服务器默认监听25端口.客户程序请求发送邮件,服务器负责将邮件传输到目的地.
    *4.client会发送一系列SMTP命令,服务器会做出响应,返回应答码及对应答码的描述
    *<pre>
    *
    *<output>
    Server>220 EX-01.hec.intra Microsoft ESMTP MAIL Service ready at Wed, 26 Jun 2013 12:56:47 +0800
    Client>HELO PC
    Server>250 EX-01.hec.intra Hello [10.130.137.44]
    Client>MAIL FROM:<wenyong.lv@happyelements.com>
    Server>550 5.7.1 Client does not have permissions to send as this sender
    Client>RCPT TO:<wenyong.lv@happyelements.com>
    Server>503 5.5.2 Need mail command
    Client>DATA
    Server>503 5.5.2 Need mail command
    Client>Subject:hello
    I just test smtp using java.
    Client>.
    Server>500 5.3.3 Unrecognized command
    Client>QUIT
    Server>500 5.3.3 Unrecognized command
    *</output>
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2013-6-25
    *
    */

    public class MailSender
    {
    private String smtpServer = "EX-01.hec.intra";//公司邮箱服务器的域名
    private int port = 25;

    private PrintWriter getWriter(Socket socket) throws IOException
    {
    OutputStream socketOut = socket.getOutputStream();
    return new PrintWriter(socketOut, true);
    }

    private BufferedReader getReader(Socket socket) throws IOException
    {
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(socketIn));
    }

    /**
    *
    * 发送一行字符串并接收服务器的响应数据
    *
    * @param str
    * @param reader
    * @param writer
    */
    private void sendAndReceive(String str,BufferedReader reader,PrintWriter writer) throws IOException
    {
    if(str != null)
    {
    System.out.println("Client>" + str);
    writer.println(str);//是println.需要发送
    }

    String response;

    if((response = reader.readLine()) != null)
    {
    System.out.println("Server>" + response);
    }
    }

    /**
    *
    * 发送邮件
    *
    * @param msg
    */
    public void sendMail(Message msg)
    {
    Socket socket = null;

    try
    {
    socket = new Socket(smtpServer,port);//连接至邮件服务器

    BufferedReader reader = getReader(socket);
    PrintWriter writer = getWriter(socket);

    String localhost = InetAddress.getLocalHost().getHostName();

    //因为连接成功时,SMTP服务器会返回一个应答码为220的响应,表示就绪.
    //214-帮助信息 220-服务就绪 221-服务关闭 250-邮件操作完成 354-开始输入邮件内容,以.结束 421-服务未就绪,关闭传输通道
    //501 命令参数格式错误 502 命令不支持 503 错误的命令序列 504 命令参数不支持
    sendAndReceive(null, reader, writer);//为了接收服务器的响应数据

    sendAndReceive("HELO " + localhost, reader, writer);//HELO | EHLO表示邮件发送者的主机地址
    sendAndReceive("MAIL FROM:<" + msg.from + ">", reader, writer);//邮件发送者的邮件地址
    sendAndReceive("RCPT TO:<" + msg.to + ">", reader, writer);//邮件接收者送者的邮件地址

    //邮件内容
    sendAndReceive("DATA", reader, writer);
    writer.println(msg.data);

    System.out.println("Client>" + msg.data);

    // 发送完毕
    sendAndReceive(".", reader, writer);

    // 退出
    sendAndReceive("QUIT", reader, writer);
    }
    catch(IOException e)
    {
    e.printStackTrace();
    }
    finally
    {
    try
    {
    if(socket != null)
    {
    socket.close();
    }
    }
    catch(IOException e)
    {
    e.printStackTrace();
    }
    }
    }

    public static void main(Stringargs)
    {
    Message message = new Message("wenyong.lv@happyelements.com",
    "wenyong.lv@happyelements.com",
    "hello",
    "I just test smtp using java.");

    new MailSender().sendMail(message);
    }
    }

    /**
    *
    * 一封邮件消息
    *
    * @author landon
    *
    */
    class Message
    {
    /** 发送者地址 */
    String from;
    /** 接收者地址 */
    String to;
    /** 标题 */
    String subject;
    /** 正文 */
    String content;
    /** 数据<标题+正文> */
    String data;

    public Message(String from,String to,String subject,String content)
    {
    this.from = from;
    this.to = to;
    this.subject = subject;
    this.content = content;

    data = "Subject:" + subject + " " + content;
    }

    }

    package com.game.landon.socket;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.InetAddress;
    import java.net.Socket;

    /**
    *
    *有些SMTP服务器要求客户提供身份认证信息.本例使用126邮箱进行测试,向qq邮箱测试,注意发送主题和内容要正规一些
    *否则发送时会被认为是垃圾邮件,不被发送
    *
    *1.先发送EHLO
    *2.发送AUTH LOGIN
    *3.采用Base64编码用户名和口令.即可通过认证.
    *
    *{@link MailSender}
    *Server>550 5.7.1 Client does not have permissions to send as this sender
    *
    *<output>
    Server>220 126.com Anti-spam GT for Coremail System (126com[20121016])
    Client>HELO PC
    Server>250 OK
    Client>AUTH LOGIN
    Server>334 dXNlcm5hbWU6
    Client>c210cGxhbmRvbg==
    Server>334 UGFzc3dvcmQ6
    Client>YTEyMzQ1Ng==
    Server>235 Authentication successful
    Client>MAIL FROM:<smtplandon@126.com>
    Server>250 Mail OK
    Client>RCPT TO:<340706410@qq.com>
    Server>250 Mail OK
    Client>DATA
    Server>354 End data with <CR><LF>.<CR><LF>
    Client>Subject:hello,我是stmplandon,测试一下stmp
    I just test smtp using java.ok??
    Client>.
    Server>250 Mail OK queued as smtp4,jdKowECpUWU+gcpR0HQUCA--.1261S2 1372225854
    Client>QUIT
    Server>221 Bye
    *</output>
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2013-6-26
    *
    */

    public class MailSenderWithAuth
    {
    private String smtpServer = "smtp.126.com";//使用126邮箱进行测试
    private int port = 25;

    private PrintWriter getWriter(Socket socket) throws IOException
    {
    OutputStream socketOut = socket.getOutputStream();
    return new PrintWriter(socketOut, true);
    }

    private BufferedReader getReader(Socket socket) throws IOException
    {
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(socketIn));
    }

    /**
    *
    * 发送一行字符串并接收服务器的响应数据
    *
    * @param str
    * @param reader
    * @param writer
    */
    private void sendAndReceive(String str,BufferedReader reader,PrintWriter writer) throws IOException
    {
    if(str != null)
    {
    System.out.println("Client>" + str);
    writer.println(str);//是println.需要发送
    }

    String response;

    if((response = reader.readLine()) != null)
    {
    System.out.println("Server>" + response);
    }
    }

    /**
    *
    * 发送邮件
    *
    * @param msg
    */
    public void sendMail(Message msg)
    {
    Socket socket = null;

    try
    {
    socket = new Socket(smtpServer,port);//连接至邮件服务器

    BufferedReader reader = getReader(socket);
    PrintWriter writer = getWriter(socket);

    String localhost = InetAddress.getLocalHost().getHostName();

    //因为连接成功时,SMTP服务器会返回一个应答码为220的响应,表示就绪.
    //214-帮助信息 220-服务就绪 221-服务关闭 250-邮件操作完成 354-开始输入邮件内容,以.结束 421-服务未就绪,关闭传输通道
    //501 命令参数格式错误 502 命令不支持 503 错误的命令序列 504 命令参数不支持
    sendAndReceive(null, reader, writer);//为了接收服务器的响应数据

    sendAndReceive("HELO " + localhost, reader, writer);//HELO | EHLO表示邮件发送者的主机地址

    sendAndReceive("AUTH LOGIN", reader, writer);//认证命令

    // 新注册的一个126账号
    String userName = new sun.misc.BASE64Encoder().encode("smtplandon".getBytes());
    String pwd = new sun.misc.BASE64Encoder().encode("a123456".getBytes());

    sendAndReceive(userName, reader, writer);
    sendAndReceive(pwd, reader, writer);

    sendAndReceive("MAIL FROM:<" + msg.from + ">", reader, writer);//邮件发送者的邮件地址
    sendAndReceive("RCPT TO:<" + msg.to + ">", reader, writer);//邮件接收者送者的邮件地址

    //邮件内容
    sendAndReceive("DATA", reader, writer);
    writer.println(msg.data);

    System.out.println("Client>" + msg.data);

    // 发送完毕
    sendAndReceive(".", reader, writer);

    // 退出
    sendAndReceive("QUIT", reader, writer);
    }
    catch(IOException e)
    {
    e.printStackTrace();
    }
    finally
    {
    try
    {
    if(socket != null)
    {
    socket.close();
    }
    }
    catch(IOException e)
    {
    e.printStackTrace();
    }
    }
    }

    public static void main(Stringargs)
    {
    Message message = new Message("smtplandon@126.com",
    "340706410@qq.com",
    "hello,我是stmplandon,测试一下stmp",
    "I just test smtp using java.ok??");

    new MailSenderWithAuth().sendMail(message);
    }
    }

    package com.game.landon.socket;

    import java.io.IOException;
    import java.net.Socket;

    /**
    *
    *扫描1到1024的端口,用Socket连接这些端口,如果Socket对象创建成功,则说明在这些端口中有服务器程序在监听
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2012-9-27
    *
    */

    public class PortScanner
    {
    public static void main(Stringargs)
    {
    String host = "localhost";

    new PortScanner().scan(host);
    }

    /**
    *
    * 扫描指定的Host下的各端口的服务器程序
    *
    * @param host
    */
    public void scan(String host)
    {
    Socket socket = null;

    for(int port = 0;port < 1024;port++)
    {
    try
    {
    //该构造方法就会试图建立与服务器的连接
    socket = new Socket(host,port);
    System.out.println("There is a Server on Port:" + port);
    }
    catch(IOException e)
    {
    System.out.println("Can't connect to port:" + port);
    }
    finally
    {
    try
    {
    if(socket != null)
    {
    socket .close();
    }
    }
    catch(IOException e)
    {
    e.printStackTrace();
    }
    }
    }
    }
    }

    package com.game.landon.socket;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.concurrent.TimeUnit;

    /**
    *
    *接收数据的服务器程序,每隔1秒接收一行字符串.共接收20行字符串
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2013-6-14
    *
    */

    public class Receiver
    {
    private int port = 8000;
    private ServerSocket serverSocket;

    private static int stopWay = 1;

    private final int NATURAL_STOP = 1;
    private final int SUDDEN_STOP = 2;
    private final int SOCKET_STOP = 3;
    private final int INPUT_STOP = 4;

    /** 关闭ServerSocket,再结束程序 */
    private final int SERVERSOCKET_STOP = 5;

    public Receiver() throws IOException
    {
    serverSocket = new ServerSocket(port);
    System.out.println("server has started.");
    }

    private BufferedReader getReader(Socket socket) throws IOException
    {
    InputStream socketIn = socket.getInputStream();

    return new BufferedReader(new InputStreamReader(socketIn));
    }

    public void receive() throws Exception
    {
    Socket socket = null;
    socket = serverSocket.accept();

    BufferedReader br = getReader(socket);

    for(int i = 0;i < 20;i++)
    {
    //client socket close后,readLine则会抛出此异常
    // Exception in thread "main" java.net.SocketException: Connection reset
    // at java.net.SocketInputStream.read(Unknown Source)
    // at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
    // at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
    // at sun.nio.cs.StreamDecoder.read(Unknown Source)
    // at java.io.InputStreamReader.read(Unknown Source)
    // at java.io.BufferedReader.fill(Unknown Source)
    // at java.io.BufferedReader.readLine(Unknown Source)
    // at java.io.BufferedReader.readLine(Unknown Source)
    // at com.game.landon.socket.Receiver.receive(Receiver.java:59)
    String msg = br.readLine();
    System.out.println("receive:" + msg);

    TimeUnit.MILLISECONDS.sleep(1000);

    if(i == 2)
    {
    //2.通过提前停止receiver.发现Sender依然会发送全部的20行字符.
    //因为进入Receiver结束运行,但是底层的Socket并没有立即释放本地端口.OS检测还没有发送给Socket的数据,会使底层Socket继续占用本地端口一段时间
    if(stopWay == SUDDEN_STOP)
    {
    System.out.println("sudden stop");
    System.exit(0);
    }
    else if(stopWay == SOCKET_STOP)
    {
    System.out.println("close socket and stop");
    socket.close();
    break;
    }
    else if(stopWay == INPUT_STOP)
    {
    System.out.println("shutdown the input and stop");
    socket.shutdownInput();
    break;
    }
    else if(stopWay == SERVERSOCKET_STOP)
    {
    System.out.println("close serverSocket and stop");
    serverSocket.close();
    break;
    }
    }
    }

    //1.server和client均已正常结束方式运行的话,因为二者sleep的时间不同.所以server可能再次read的时候会出现异常:
    //Exception in thread "main" java.net.SocketException: Connection reset
    //at java.net.SocketInputStream.read(Unknown Source)
    //这样的话,其实server可能会丢失读了部分数据(Connection reset.Client的Socket已经close了->client的数据可能还在网络传输,即还未被接收方接收).
    //查一下是否是Socket选项问题
    if(stopWay == NATURAL_STOP)
    {
    socket.close();
    serverSocket.close();
    }
    }

    public static void main(String[] args) throws Exception
    {
    if(args.length > 0)
    {
    stopWay = Integer.parseInt(args[0]);
    }

    new Receiver().receive();
    }
    }

    package com.game.landon.socket;

    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketTimeoutException;

    /**
    *
    *读取SendClient发送来的数据,直到抵达输入流的末尾
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2013-6-18
    *
    */

    public class ReceiveServer
    {
    public static void main(Stringargs) throws Exception
    {
    ServerSocket serverSocket = new ServerSocket(8000);

    Socket socket = serverSocket.accept();
    // 设置接收数据的等待时间
    socket.setSoTimeout(3 * 1000);

    InputStream in = socket.getInputStream();
    ByteArrayOutputStream bufferStream = new ByteArrayOutputStream();
    byte[] buff = new byte[1024];

    int len = -1;

    do
    {
    try
    {
    //1.启动ReceiveServer再启动SendClient.->因为client至发送了helloworld.所以不能读到足够的数据填满buff.->一直等待->client睡眠结束,关闭Socket
    //->ReceiverServer读到输入流末尾->立即结束等待->read返回-1.
    //2.启动ReceiveServer再启动SendClient->in.read一直在等待->在client随眠期间,关掉client->抛出Exception in thread "main" java.net.SocketException: Connection reset
    //3.socket.setSoTimeout(3 * 1000)->加上这个后,in.read则会超时抛出异常
    len = in.read(buff);

    if(len != -1)
    {
    bufferStream.write(buff, 0, len);
    }
    }
    catch(SocketTimeoutException e)
    {
    System.err.println("read timeout");
    len = 0;
    }
    }
    while(len != -1);

    System.out.println(new String(bufferStream.toByteArray()));
    }
    }

    package com.game.landon.socket;

    import java.io.OutputStream;
    import java.net.Socket;
    import java.util.concurrent.TimeUnit;

    /**
    *
    *发送字符串->sleep->关闭Socket
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2013-6-18
    *
    */

    public class SendClient
    {
    public static void main(Stringargs) throws Exception
    {
    Socket socket = new Socket("localhost",8000);
    OutputStream out = socket.getOutputStream();

    out.write("hello".getBytes());
    out.write("world".getBytes());

    // sleep
    TimeUnit.MILLISECONDS.sleep(5 * 1000);

    socket.close();
    }
    }

    package com.game.landon.socket;

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.util.concurrent.TimeUnit;

    /**
    *
    * 发送数据的客户程序,每隔500毫秒发送一行字符串.共发送20行字符串
    *
    * @author landon
    * @since 1.6.0_35
    * @version 1.0.0 2013-6-14
    *
    */

    public class Sender
    {
    private String host = "localhost";
    private int port = 8000;
    private Socket socket;

    /** 结束通信的方式 */
    private static int stopWay;

    /** 自然结束 */
    private final int NATURAL_STOP = 1;
    /** 突然终止程序 */
    private final int SUDDEN_STOP = 2;
    /** 关闭Socket,再结束程序 */
    private final int SOCKET_STOP = 3;
    /** 关闭输出流,再结束程序 */
    private final int OUTPUT_STOP = 4;

    public static void main(Stringargs) throws Exception
    {
    if(args.length > 0)
    {
    stopWay = Integer.parseInt(args[0]);
    }

    new Sender().send();
    }

    public Sender() throws IOException
    {
    socket = new Socket(host, port);
    }

    private PrintWriter getWriter(Socket socket) throws IOException
    {
    return new PrintWriter(socket.getOutputStream(), true);
    }

    public void send() throws Exception
    {
    PrintWriter pw = getWriter(socket);

    for(int i = 0;i < 20;i++)
    {
    String msg = "hello_" + i;
    pw.println(msg);

    System.out.println("send:" + msg);

    TimeUnit.MILLISECONDS.sleep(500);

    if(i == 2)
    {
    //1.sender突然中止,server会抛出:Exception in thread "main" java.net.SocketException: Connection reset
    //at java.net.SocketInputStream.read(Unknown Source)
    if(stopWay == SUDDEN_STOP)
    {
    System.out.println("sudden stop");
    System.exit(0);
    }
    else if(stopWay == SOCKET_STOP)
    {
    System.out.println("socket close");
    socket.close();
    break;
    }
    else if(stopWay == OUTPUT_STOP)//2.如果send以这种方式运行,则server会出现:receive:null receive:null receive:null.
    //因为已经shutdownOutput.server调用readLine方法时读到了输入流的末尾,因为返回null
    {
    System.out.println("socket shutdown outputstream");
    socket.shutdownOutput();
    break;
    }
    }
    }

    if(stopWay == NATURAL_STOP)
    {
    socket.close();
    }
    }
    }

    package com.game.landon.socket;

    import java.net.Socket;

    /**
    *
    *simple client,用来测试服务器的连接请求队列的长度
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2012-10-9
    *
    */

    public class SimpleClient
    {
    public static void main(Stringargs) throws Exception
    {
    Socket s1 = new Socket("localhost",8000);
    System.out.println("第一次连接成功");
    Socket s2 = new Socket("localhost",8000);
    System.out.println("第二次连接成功");
    //这里会抛出异常
    //Exception in thread "main" java.net.ConnectException: Connection refused: connect
    Socket s3 = new Socket("localhost",8000);
    System.out.println("第三次连接成功");

    }
    }

    package com.game.landon.socket;

    import java.net.ServerSocket;

    /**
    *
    *一个SimpleServer,用来测试服务器的连接请求队列的长度
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2012-10-9
    *
    */

    public class SimpleServer
    {
    public static void main(Stringargs) throws Exception
    {
    //设置连接请求队列的长度为2
    ServerSocket serverSocket = new ServerSocket(8000,2);//ServerSocket(int port,int backlog)
    Thread.sleep(6 * 60 * 1000);//sleep 6分钟

    // 个人认为这个连接请求队列只有在server端将连接的socket断掉后,才会从队列移除(属个人猜测)
    }
    }

    package com.game.landon.socket;

    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.Socket;

    /**
    *
    *测试BindException
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2012-10-9
    *
    */

    public class TestBindException
    {
    public static void main(Stringargs) throws Exception
    {
    Socket socket = new Socket();
    //直接运行程序,即抛出Exception in thread "main" java.net.BindException: Cannot assign requested address: JVM_Bind
    // socket.bind(new InetSocketAddress(InetAddress.getByName("10.10.0.0"),5678));

    // 抛出异常:Exception in thread "main" java.net.BindException: Address already in use: JVM_Bind
    socket.bind(new InetSocketAddress("127.0.0.1", 3306));//3306为mysql所占端口

    // Socket socket = new Socket("localhost",80,InetAddress.getByName("10.10.0.0"),5678);
    }
    }

    package com.game.landon.socket;

    import java.io.OutputStream;
    import java.net.Socket;

    /**
    *
    *测试SO_LINGER选项的一个client.发送100个字符(10000个的话控制台就显示不出来了)给Server.然后调用close关闭Socket
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2013-6-18
    *
    */

    public class TestLingerClient
    {
    public static void main(Stringargs) throws Exception
    {
    Socket socket = new Socket("localhost",8000);

    // socket.setSoLinger(true, 0);
    socket.setSoLinger(true, 60);

    OutputStream out = socket.getOutputStream();
    StringBuilder builder = new StringBuilder();

    for(int i = 0;i < 100;i++)
    {
    builder.append(i);
    }

    //1.注释掉两句setSoLinger的代码->启动Server再启动client.
    //1.close方法立即返回 输出close socket cost Time:0 ms
    //2.因为server执行了sleep->client已经执行了close且client程序本身也结束了->但是server依然受到了全部所有的数据.
    //因为client执行了Socket#close后,底层的Socekt其实并没有真正关闭,与server的连接仍然存在.底层的Socket会存在一段时间,知道发送完所有的数据.
    //2.socket.setSoLinger(true, 0)->先后启动server|client.->client执行Socket#close时会强制关闭底层Socket.->所有未发送数据丢失.->Server
    //结束休眠后,读数据抛出异常->Exception in thread "main" java.net.SocketException: Connection reset
    //3.socket.setSoLinger(true, 60)->先后启动server|client->client执行Socket#close会阻塞状态,直到等待了60秒.->或者底层已经将所有未发送的数据
    //发送完毕,才会从close返回。
    //close socket cost Time:1651 ms->server结束休眠后,因为client还在执行close并处于阻塞状态.client与server之前的连接依然存在.所以可以收到所有数据.
    out.write(builder.toString().getBytes());//发送100个字符

    long begin = System.currentTimeMillis();
    socket.close();
    long end = System.currentTimeMillis();

    System.out.println("close socket cost Time:" + (end - begin) + " ms");
    }
    }

    package com.game.landon.socket;

    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;

    /**
    *
    *测试SO_LINGER选项的一个简单server.接收连接请求后,不立即接收client发送的数据,而是睡眠5秒再接收数据.
    *等到其开始接收数据时,client可能已经执行了close方法.server还会接收到client发送的数据吗?
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2013-6-18
    *
    */

    public class TestLingerServer
    {
    public static void main(String[] args) throws Exception
    {
    ServerSocket serverSocket = new ServerSocket(8000);
    Socket socket = serverSocket.accept();

    Thread.sleep(5000);//睡眠5秒再读输入流

    InputStream in = socket.getInputStream();
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    byte[] buff = new byte[1024];

    int len = -1;

    do
    {
    len = in.read(buff);

    if(len != -1)
    {
    buffer.write(buff, 0, len);
    }
    }
    while (len != -1);

    System.out.println(new String(buffer.toByteArray()));//字节数组转为字符串
    }
    }

    package com.game.landon.socket;

    /**
    *
    *测试String字符串长度问题
    *
    *@author landon
    *@since 1.6.0_35
    *@version 1.0.0 2013-6-18
    *
    */

    public class TestStringMax
    {
    public static void main(String[] args)
    {
    StringBuilder builder = new StringBuilder();

    for(int i = 0;i < 10000;i++)
    {
    builder.append(i);
    }

    // 打印出了长度
    System.out.println(builder.toString().length());
    // 但是字符串却无法打印,原因是控制台设置的原因->Window->Preferences->Run/Debug->Console->Fixed with Console->Maximum Character Width
    System.out.println(builder.toString());
    }
    }

  • 相关阅读:
    k8S 搭建集群
    K8S搭建
    华为交换机常用命令
    JSP中动态include和静态include的区别
    什么情况下调用doGet()和doPost()
    get和post的区别
    什么是spring框架
    spring的作用
    什么是DI
    依赖注入的三种实现方式
  • 原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/5472052.html
Copyright © 2020-2023  润新知