前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java Socket与ServerSocket 详解

java Socket与ServerSocket 详解

作者头像
Java编程指南
发布2019-08-02 16:17:02
1.5K0
发布2019-08-02 16:17:02
举报

socket 介绍

我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。

能够唯一标示网络中的进程后,它们就可以利用socket进行通信了,什么是socket呢?我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。

socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

socket 通讯详解

socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概是这样子的

三次握手

在TCP/IP协议中,TCP协议通过三次握手建立一个可靠的连接

第一次握手:客户端尝试连接服务器,向服务器发送syn包(同步序列编号Synchronize Sequence Numbers),syn=j,客户端进入SYN_SEND状态等待服务器确认

第二次握手:服务器接收客户端syn包并确认(ack=j+1),同时向客户端发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态

第三次握手:第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手

定睛一看,服务器socket与客户端socket建立连接的部分其实就是大名鼎鼎的三次握手

socket 异常讲解

在了解Socket的内容之前,先要了解一下涉及到的一些异常类型。以下四种类型都是继承于IOException,所以很多之后直接弹出IOException即可。

UnkownHostException:   主机名字或IP错误

ConnectException:     服务器拒绝连接、服务器没有启动、(超出队列数,拒绝连接)

SocketTimeoutException: 连接超时

BindException:       Socket对象无法与制定的本地IP地址或端口绑定

socket api 讲解

Socket与ServerSocket的交互,下面的图片我觉得已经说的很详细很清楚了。

Socket

构造函数

Socket()

Socket(InetAddress address, int port)throws UnknownHostException, IOException

Socket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException

Socket(String host, int port)throws UnknownHostException, IOException

Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException

除去第一种不带参数的之外,其它构造函数会尝试建立与服务器的连接。如果失败会抛出IOException错误。如果成功,则返回Socket对象。

InetAddress是一个用于记录主机的类,其静态getHostByName(String msg)可以返回一个实例,其静态方法getLocalHost()也可以获得当前主机的IP地址,并返回一个实例。Socket(String host, int port, InetAddress localAddress, int localPort)构造函数的参数分别为目标IP、目标端口、绑定本地IP、绑定本地端口。

Socket方法

getInetAddress(); 远程服务端的IP地址

getPort(); 远程服务端的端口

getLocalAddress() 本地客户端的IP地址

getLocalPort() 本地客户端的端口

getInputStream(); 获得输入流

getOutStream(); 获得输出流

值得注意的是,在这些方法里面,最重要的就是getInputStream()和getOutputStream()了。

Socket状态

isClosed(); //连接是否已关闭,若关闭,返回true;否则返回false

isConnect(); //如果曾经连接过,返回true;否则返回false

isBound(); //如果Socket已经与本地一个端口绑定,返回true;否则返回false

如果要确认Socket的状态是否处于连接中,下面语句是很好的判断方式。

boolean isConnection=socket.isConnected() && !socket.isClosed();   //判断当前是否处于连接

半关闭Socket

很多时候,我们并不知道在获得的输入流里面到底读多长才结束。下面是一些比较普遍的方法:

  • 自定义标识符(譬如下面的例子,当受到“bye”字符串的时候,关闭Socket)
  • 告知读取长度(有些自定义协议的,固定前几个字节表示读取的长度的)
  • 读完所有数据
  • 当Socket调用close的时候关闭的时候,关闭其输入输出流

ServerSocket

构造函数

ServerSocket()throws IOException

ServerSocket(int port)throws IOException

ServerSocket(int port, int backlog)throws IOException

ServerSocket(int port, int backlog, InetAddress bindAddr)throws IOException

注意点:

1. port服务端要监听的端口;backlog客户端连接请求的队列长度;bindAddr服务端绑定IP

2. 如果端口被占用或者没有权限使用某些端口会抛出BindException错误。譬如1~1023的端口需要管理员才拥有权限绑定。

3. 如果设置端口为0,则系统会自动为其分配一个端口;

4. bindAddr用于绑定服务器IP,为什么会有这样的设置呢,譬如有些机器有多个网卡。

5. ServerSocket一旦绑定了监听端口,就无法更改。ServerSocket()可以实现在绑定端口前设置其他的参数。

单线程的ServerSocket例子

public void service(){ 
 while(true){
 Socket socket=null; try{
 socket=serverSocket.accept();//从连接队列中取出一个连接,如果没有则等待
 System.out.println("新增连接:"+socket.getInetAddress()+":"+socket.getPort());
 ...//接收和发送数据
 }catch(IOException e){e.printStackTrace();}finally{ 
 try{ 
 if(socket!=null) socket.close();//与一个客户端通信结束后,要关闭Socket
 }catch(IOException e)
 {e.printStackTrace();
 }
 }
 }
}                                                                                                          
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java编程指南 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • socket 通讯详解
    • 三次握手
    • socket 异常讲解
    • socket api 讲解
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档