java网络编程socket解析

时间:2021-12-21 09:33:19

转载: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\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());
}
}

java网络编程socket解析的更多相关文章

  1. java网络编程socket&bsol;server&bsol;TCP笔记(转)

    java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅     1 TCP的开销 a ...

  2. Java网络编程——Socket

    网络是连接不同计算机的媒介,不同的计算机依靠网络来互相通信,即传递数据. Java中与网络编程相关的部分主要是Socket(套接字),它作为一种抽象的结构,实现了与通信相关的各类方法,构成一套完整的通 ...

  3. java网络编程Socket通信详解

    Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket.像大家熟悉的QQ.MSN都使用了Socket相关的技术. ...

  4. java网络编程——socket实现简单的CS会话

    还记得当年学计网课时用python实现一个简单的CS会话功能,这也是学习socket网络编程的第一步,现改用java重新实现,以此记录. 客户端 import java.io.*; import ja ...

  5. JAVA网络编程Socket常见问题 【长连接专题】

    一. 网络程序运行过程中的常见异常及处理 第1个异常是 java.net.BindException:Address already in use: JVM_Bind. 该异常发生在服务器端进行new ...

  6. java 网络编程Socket

    TCP: 通过TCP协议传输,得到的是一个顺序的无差错的数据流. 发送方和接收方的成对的两个socket之间必须建立连接, 以便在TCP协议的基础上进行通信,当一个socket(通常都是server ...

  7. java 网络编程Socket编程

    Server.java import java.io.*; import java.net.*; public class Server { public static void main(Strin ...

  8. Java网络编程Socket通信

        TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议     UDP (User Datagram Proto ...

  9. java网络编程socket的使用

    Socket 客户端实例 如下的 GreetingClient 是一个客户端程序,该程序通过 socket 连接到服务器并发送一个请求,然后等待一个响应. GreetingClient.java 文件 ...

随机推荐

  1. docker--初体验

    docker这个词已经越来越热,很多docker的概念是从周围人和知乎上看的,打算从功能上先了解docker,深入的话放在以后. ps:正好手头有一台腾讯云的vps,单核,1G内存,可以拿来做实验,腾 ...

  2. python中的 &lowbar;&lowbar;slots&lowbar;&lowbar;

    __slots__的作用是防止给class instance分配dict,达到控制instance 成员和节省内存的作用 class Slots(object): __slots__=("n ...

  3. hive外部表的建立与数据匹配

    1.建立hive的外部表匹配hdfs上的数据 出现如下报错: hive (solar)> ; OK Failed with exception java.io.IOException:java. ...

  4. Wireshark分析器分析数据流过程

    Wireshark分析器分析数据流过程 分析包是Wireshark最强大的功能之一.分析数据流过程就是将数据转换为可以理解的请求.应答.拒绝和重发等.帧包括了从捕获引擎或监听库到核心引擎的信息.Wir ...

  5. 历时一周,unity3d&plus;xtion打造我的第一个休闲体感小游戏《空降奇兵》

    1.游戏介绍 本游戏属于休闲小游戏,主要操作如下: 菜单控制:举起左手或右手,点击左边或者右边的菜单:挥动左手或右手,选择关卡: 操作方式:玩家跳跃,游戏中的伞兵从飞机开始降落:玩家通过控制伞兵的左右 ...

  6. 如何设置lmt的空间警告阀值

    Example—设置Locally Managed Tablespace的空间警告阀值 The following example sets the free-space-remaining thre ...

  7. css遗漏

    对于float浮动 子级元素浮动之后,因为元素脱离了文档流所以父级元素的高度不会auto而是变成0的解决方案 父级元素增加伪类 父级:after{ content:""; disp ...

  8. 第28篇 js中let和var

      let与var 在js中声明一个变量除了一个var 还有一个let的声明.对于var 在前面的作用域中已经讲过,这次主要说下二者的区别: 在MDN上有这样的一个demo: var list = d ...

  9. filezilla里怎么解决中文乱码问题

    使用Filezilla client FTP客户端登陆某些FTP站点会出现中文乱码,原因是FTP服务器端编码与filezilla client端编码不一致造成的.解决方法如下:文件-站点管理-选中要登 ...

  10. bzoj3884 上帝的集合

    根据一些书上的记载,上帝的一次失败的创世经历是这样的: 第一天, 上帝创造了一个世界的基本元素,称做“元”. 第二天, 上帝创造了一个新的元素,称作“α α ”.“α α 被定义为“元”构成的集合.容 ...