SOCKET

Socket

Socket实际上就是IP +协议+port
位于应用层和传输层的一个抽象层
在这里插入图片描述

TCP中的socket

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法介绍

客户端
  1. 构造函数
    Socket socket = new Socket(Proxy.NO_PROXY);等于无参构造
    带代理构造
    Proxy proxy = new Proxy(Proxy.Type.HTTP/DIREC/SOCKS, new InetSocketAddress(Inet4Address.getByName("“www.baidu.com”),prot:8800));
    Socket socket = new Socket(proxy)

Socket socket = new Socket(本地PORT//Inet4Address.getLocalHost(),PORT);//建立socket连接本地的PORT;

Socket socket = new Socket(远程的host,远程的port,本地的host,本地的端口);

Socket socket = new Socket();
socket.bind(new InetSocketAddress(Inet4Address.getLocalHost(),LOCAL_PORT));
socket.connect(); 上面一行等于这个三行 有bind 有 connect

  1. 初始化
    设置读取超时时间
    socket.setSoTimeout
    是否复用未完成关闭的Socket地址 对于bind后的套接字有效
    socket.setReuseAddress(true); 一般连接结束后 两分钟内不能再次使用
    socket.setTcpNoDelay(true);//是否开启Nagle算法
    socket.setKeepAlive(true); //长时间无数据响应发送确认数据,如果没有收到回送则认为连接中断,会抛出异常
    socket.setSoLinger(true,200);//默认情况是false,0 调用close关闭,底层系统接管输出流,将缓冲区域发送完成
    设置为true,0 关闭立即返回 缓冲区的数据直接抛弃 直接发送RST结束命令 无需经过2MSL时间等待
    true,200 关闭最长阻塞时间为200ml 随后按第二种情况处理
    socket.setOOBInline(false); 是否让紧急数据接收,不建议开启会和行为数据混杂
    setSendBufferSize
    setReceiveBufferSize 缓冲区大小 如果小于这个值就直接发 不然就拆分
    setPerformancePreferences(短连接,延迟,带宽)的权重
  2. 连接操作
    socket.connect(new InetSocketAddress(IP,PORT))
服务端
  1. 创建
    ServerSocket ss = new ServerSocket();
    ss.bind(new InetSocket(Inet4Address.getLocalHost(),PORT),50);
    允许等待的队列为50个 超过50个会在客户端超过异常
    同样建议使用空的构造函数在初始化之后进行绑定
  2. 初始化
    setReuseAddress
    setReceiveBufferSize
    setSoTimeout//设置accept 的超时时间
    setPerformancePreferences
一些重要方法
  1. listen()函数
    int listen(SOCKET sock, int backlog); //Windows
    listen() 函数的主要作用就是将 socket() 函数得到的 sockfd 从 主动连接变成一个被动监听的套接字, 用来被动等待客户端的连接, 而参数 backlog 的作用就是设置连接队列的长度
  2. 如果有客户端通过 connect() 发起连接请求, 内核就会通过三次握手建立连接, 然后将建立好的连接放到已完成连接队列
    通常客户端通过 connect() 函数来向服务端主动发起连接, 通知内核通过三次握手建立连接, 然后将结果返回给这个函数. 这个函数默认会一直阻塞, 直到内核连接建立成功或者超时失败才返回(但一般这个过程很快)
    服务器端通过 listen() 函数来通知内核建立连接,
    客户端通过 connect() 函数来通知内核建立连接
    如果在 listen 之后不进行 accept , connect 也是会成功返回的, 其实此时连接就已经建立好了
  3. accept() 函数的作用就是在已完成连接队列中取出一个已经建立好的连接
    如果这个队列中已经没有已完成连接的套接字, 那么 accept() 就会一直阻塞, 直到取得一个已经建立连接的套接字
  4. shutdown()
    调用 close()/closesocket() 函数意味着完全断开连接,即不能发送数据也不能接收数据,这种“生硬”的方式有时候会显得不太“优雅”。
    int shutdown(SOCKET s, int howto);
    SD_RECEIVE:关闭接收操作,也就是断开输入流。
    SD_SEND:关闭发送操作,也就是断开输出流。
    SD_BOTH:同时关闭接收和发送操作。
    close()和shutdown()的区别
    确切地说,close()用来关闭套接字,之后再也不能使用该套接字,与C语言中的 fclose() 类似。应用程序关闭套接字后,与该套接字相关的连接和缓存也失去了意义,TCP协议会自动触发关闭连接的操作。
    shutdown() 用来关闭连接,直到调用 close() 将套接字从内存清除。
    调用 close()/closesocket() 关闭套接字时,或调用 shutdown() 关闭输出流时,都会向对方发送 FIN 包。FIN 包表示数据传输完毕,计算机收到 FIN 包就知道不会再有数据传送过来了。
    默认情况下,close()会立即向网络中发送FIN包,不管输出缓冲区中是否还有数据,而shutdown() 会等输出缓冲区中的数据传输完毕再发送FIN包。也就意味着,调用 close() 将丢失输出缓冲区中的数据,而调用 shutdown() 不会。
  5. send() recv()
    int send(SOCKET sock, const char *buf, int len, int flags);
    int recv(SOCKET sock, const char *buf, int len, int flags);
    sock 为要发送数据的套接字,buf 为要发送的数据的缓冲区地址,len 为要发送的数据的字节数

UDP的socket

使用DatagramSocket 和 Datagrampacket

发送端

  • 建立DatagramSocket服务;
  • 提供数据,并把数据封装到字节数组中
  • 创建DatagramPacket数据包,将数据封装到包中,同时指定IP和接收端口
  • 通过Socket服务,利用send方法将数据包发出去
  • 关闭DatagramSocket 和 Datagrampacket

接收端

  • 建立DatagramSocket服务 并且监听一个端口;
  • 定义一个Byte[]字节数组 和一个Datagrampacket数据包,并把数组封装进数据包
  • 调用DatagramPacket的receive的方法,将接收数据存入到包中
  • 关闭DatagramSocket 和 Datagrampacket

具体方法

  • DatagramSocket相关的方法
    DatagramSocket()
    构造数据包的套接字并绑定本地主机上任何可用的端口
    DatagramSocket(int port)
    绑定指定的端口
    DatagramSocket(int port, IntetAddress addr)
    绑定到本地地址
    close()
    关闭套接字
    InetAddress getInetAddress()
    返回与套接字连接的地址
    InetAddress getLocalAddress()
    获取绑定的本地地址
    int getPort()
    返回套接字的端口
    void receive(DatagramPacket p)
    从套接字接收数据报
    void sendDatagramPacket p)
    从套接字发送数据报

  • DatagramPacket的方法
    DatagramPacket(byte[] buf,int length)
    构造DatagramPacket,用来接收长度为length的数据报
    DatagramPacket(byte[] buf,int length,int port, IntetAddress addr)
    用来将长度为length的数据包发送到指定主机的指定端口号上
    InetAddress getAddress()
    返回某台机器的IP地址
    byte() getData()
    返回数据缓冲区
    int getLength()
    返回数据的长度
    int getPort()
    返回远程主机的端口号
    setData(byte[] buf, int length ,int offset)
    setLength

粘包问题

例如,write()/send() 重复执行三次,每次都发送字符串"abc",那么目标机器上的 read()/recv() 可能分三次接收,每次都接收"abc";也可能分两次接收,第一次接收"abcab",第二次接收"cabc";也可能一次就接收到字符串"abcabcabc"。

这就是数据的“粘包”问题,客户端发送的多个数据包被当做一个数据包接收。也称数据的无边界性,read()/recv() 函数不知道数据包的开始或结束标志(实际上也没有任何开始或结束标志),只把它们当做连续的数据流来处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值