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\r\n");
 sb.append("Host:www.javathinker.org\r\n");
 sb.append("Accept:*/*\r\n");
 sb.append("Accept-Language:zh-cn\r\n");
 sb.append("Accept-Encoding:gzip,deflate\r\n");
 sb.append("User-Agent:Mozilla/4.0(compatible;MSIE 6.0;Window NT 5.0)\r\n");
 sb.append("Connection:Keep-Alive\r\n\r\n");

 //发出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\r\n");
 sb.append("Host:www.javathinker.org\r\n");
 sb.append("Accept:*/*\r\n");
 sb.append("Accept-Language:zh-cn\r\n");
 sb.append("Accept-Encoding:gzip,deflate\r\n");
 sb.append("User-Agent:Mozilla/4.0(compatible;MSIE 6.0;Window NT 5.0)\r\n");
 sb.append("Connection:Keep-Alive\r\n\r\n");

 //发出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.需要发送\r\n
 }

 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 + "\r\n" + 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.需要发送\r\n
 }

 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());
 }
}