Socket基础
1.OSI模型
物理层 传输用的物理介质,以bit(0或1)流传输,Hub就在此层
数据链路层 节点间传输,检测传输中的差错,以帧(二进制数据组成)为单位,Switch在该层
网络层 IP协议在该层,选择不同的网络,以数据包(由帧组成)为单位,路由Router在该层
传输层 传输数据,单位为报文,TCP、UDP协议就在传输层
会话层 管理进程之间的会话过程
表示层 数据的加密解密压缩与解压缩等
应用层 http、FTP、telnet等协议在该层
2.TCP/IP模型
应用层 ftp、telent、http,与OSI类似
传输层 tcp、udp
网络层 IP
主机-物理层 以太网
3.URL
统一资源定位器 Uniform Resource Locator
网址属于URL,由协议://主机地址/路径
通过ARP协议找到物理地址
4.TCP/UDP
使用端口进行标识
检测端口 start telent 127.0.0.1 9090
查看端口 netstat -ano
关闭端口 ntsd -c q -p PID
5.Socket基础
设置连接超时,设为0则不会超时
SocketAddress sa = new InetSocketAddress("localhost",8080);
socket.connect(sa,1000);
Socket地址可以使用字符串,或者InetAddress类来表示
Socket对象包含了一些信息
getInetAddress主机地址
getPort 端口
getLocalAddress 本地地址
getLocalPort 本地端口
getInputStream
getOutputStream
Socket关闭
socket.close()
isClosed();是否关闭
isConnected();是否连接过
isBound();是否已经绑定本地端口
只关闭流,不关闭连接
shutdownInput 关闭输入流
shutdownOutput 关闭输出流
同样可以检测是否已经关闭
isInputShutdown
isOutputShutdown
Socket选项
立即发送数据
if(!socket.getTcpNoDelay()){
socket.setTcpNoDelay(true);
}
Socket关闭,暂未释放端口时,允许重用端口
if(!socket.getResouceAddress()){
socket.setResouseAddress(true);
}
等待超时
例如定义byte[1024]大小的空间,那么只有读取到byte数组中才会返回读取的字节数
超时默认为0,即无限制
if(socket.getTimeout == 0){socket.setTimeout(5000);}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <span>// 服务端 2 public static void main(String[] args) { 3 // 创建Socket服务端 4 try { 5 ServerSocket server = new ServerSocket(8080); 6 // 等待客户端连接 7 Socket s = server.accept(); 8 // 获得Socket的输入流 9 InputStream in = s.getInputStream(); 10 // 字节数组输出流,数据会写入内存缓冲区 11 // 此过滤流好处是可以输出字节数组 12 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 13 byte[] buff = new byte[1024]; 14 s.setSoTimeout(1000); 15 int len = -1; 16 try { 17 while((len=in.read(buff))!=-1){ 18 // 读取buff大小 19 buffer.write(buff,0,len); 20 } 21 } catch (Exception e) { 22 System.out.println("超时"); 23 } 24 // 超时时,仍可读取缓冲区中的数据 25 System.out.println(new String(buffer.toByteArray())); 26 } catch (Exception e) { 27 e.printStackTrace(); 28 } 29 }</span>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <span>// 客户端 2 public static void main(String[] args) { 3 try { 4 // 创建Socket连接 5 Socket s = new Socket("192.168.1.11",8080); 6 // 取得Socket的输出流 7 OutputStream out = s.getOutputStream(); 8 out.write("java socket".getBytes()); 9 out.write("hello world".getBytes()); 10 Thread.sleep(2000); 11 //s.shutdownOutput(); 12 s.close(); 13 } catch (Exception e) { 14 e.printStackTrace(); 15 } 16 }</span>
Socket关闭,底层是否立即关闭
调用close方法时,底层socket不会立即关闭,直到数据发送完才会真正关闭
linger徘徊的意思
// 立即关闭,未发送的数据丢失
socket.setSoLinger(true,0);
// 如果数据发送完,则关闭,或延迟3000
socket.setSoLinger(true,3000);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <span>// 客户端 2 public static void main(String[] args) { 3 try { 4 Socket s = new Socket("localhost",8080); 5 // 当加入此方法时,客户端关闭,服务端则不能收到数据,并且会报超时的异常 6 // 如果没有调用setSoLinger方法,即使客户端关闭,服务端仍然可以收到数据 7 s.setSoLinger(true, 0); 8 OutputStream out = s.getOutputStream(); 9 out.write("111111111111".getBytes()); 10 System.out.println("关闭socket"); 11 // 计算关闭socket所需的时间 12 long begin = System.currentTimeMillis(); 13 s.close(); 14 long end = System.currentTimeMillis(); 15 System.out.println(end-begin); 16 } catch (Exception e) { 17 e.printStackTrace(); 18 } 19 }</span>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <span>// 服务端 2 public static void main(String[] args) { 3 try { 4 ServerSocket server = new ServerSocket(8080); 5 Socket s = server.accept(); 6 // 休眠过后再读取数据 7 try { 8 Thread.sleep(6000); 9 } catch (InterruptedException e) { 10 } 11 InputStream in = s.getInputStream(); 12 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 13 byte[] buff = new byte[1024]; 14 int len = -1; 15 while((len=in.read(buff))!=-1){ 16 buffer.write(buff,0,len); 17 } 18 System.out.println(new String(buffer.toByteArray())); 19 } catch (IOException e) { 20 e.printStackTrace(); 21 } 22 }</span>
接收数据缓冲区的大小
socket.setReceiveBufferSize(1024);
socket.getReceiveBufferSize();
发送数据缓冲区大小
socket.setSendBufferSize(1024);
socket.getSendBufferSize();
Socket处于空闲时是否关闭
默认TCP不会监视连接是否有效,当设置为true时则超过一定时间会发送数据包检测
if(!socket.getKeepAlive()){
socket.setKeepAlive(true);
}
发送紧急数据
socket.setOOBInline(true);
默认值为false,接收方不会对紧急数据作处理