3、 网络IO:Socket编程BIO和TCP参数(socket网络编程流程图)

  本篇文章为你整理了3、 网络IO:Socket编程BIO和TCP参数(socket网络编程流程图)的详细内容,包含有socket编程 socket网络编程流程图 socket编程之connect socket编程tcp服务器端连接过程 3、 网络IO:Socket编程BIO和TCP参数,希望能帮助你了解 3、 网络IO:Socket编程BIO和TCP参数。

   private static final int RECEIVE_BUFFER = 10;

   private static final int SO_TIMEOUT = 0;

   private static final boolean REUSE_ADDR = false;

   private static final int BACK_LOG = 2; // 设置处理客户端请求的线程数量

   //client socket listen property on server endpoint:

   private static final boolean CLI_KEEPALIVE = false; // 是否是长连接

   private static final boolean CLI_OOB = false; // 连接断开时是否试探一下连接

   private static final int CLI_REC_BUF = 20; // Recv,接受到的数据

   private static final boolean CLI_REUSE_ADDR = false; // 是否重定地址

   private static final int CLI_SEND_BUF = 20;

   private static final boolean CLI_LINGER = true; // 断开连接速度

   private static final int CLI_LINGER_N = 0;

   private static final int CLI_TIMEOUT = 0; // 读取超时设置

   private static final boolean CLI_NO_DELAY = false; // 是否开启缓存

   StandardSocketOptions.TCP_NODELAY

   StandardSocketOptions.SO_KEEPALIVE

   StandardSocketOptions.SO_LINGER

   StandardSocketOptions.SO_RCVBUF

   StandardSocketOptions.SO_SNDBUF

   StandardSocketOptions.SO_REUSEADDR

  
server.bind(new InetSocketAddress(9090), BACK_LOG);

   server.setReceiveBufferSize(RECEIVE_BUFFER);

   server.setReuseAddress(REUSE_ADDR);

   server.setSoTimeout(SO_TIMEOUT);

   } catch (IOException e) {

   e.printStackTrace();

   System.out.println("server up use 9090!");

   try {

   while (true) {

   // System.in.read(); //分水岭:ServerSocket连接后,必须回车确认,不然不会往下走

   // 开始采用处理客户端请求,只有执行这一行代码,内核才会分配建立3次握手后的网络连接的文件描述符,也就是这个返回的Socket,java里面包装成了这个对象

   Socket client = server.accept(); //阻塞的,没有 -1 一直卡着不动 accept(4,

   System.out.println("client port: " + client.getPort());

   client.setKeepAlive(CLI_KEEPALIVE);

   client.setOOBInline(CLI_OOB);

   client.setReceiveBufferSize(CLI_REC_BUF);

   client.setReuseAddress(CLI_REUSE_ADDR);

   client.setSendBufferSize(CLI_SEND_BUF);

   client.setSoLinger(CLI_LINGER, CLI_LINGER_N);

   client.setSoTimeout(CLI_TIMEOUT);

   client.setTcpNoDelay(CLI_NO_DELAY);

   //client.read //阻塞 没有 -1 0

   new Thread(

   () - {

   try {

   // 拿到客户端输入流

   InputStream in = client.getInputStream();

   BufferedReader reader = new BufferedReader(new InputStreamReader(in));

   char[] data = new char[1024];

   while (true) {

   int num = reader.read(data);

   // 打印读取到客户端的数据

   if (num 0) {

   System.out.println("client read some data is :" + num + " val :" + new String(data, 0, num));

   } else if (num == 0) {

   System.out.println("client readed nothing!");

   continue;

   } else {

   System.out.println("client readed -1..."); // -1表示客户端断开了

   System.in.read();

   client.close();

   break;

   } catch (IOException e) {

   e.printStackTrace();

   ).start();

   } catch (IOException e) {

   e.printStackTrace();

   } finally {

   try {

   server.close();

   } catch (IOException e) {

   e.printStackTrace();

  

 

 

  客户端的测试代码:

  

import java.io.*;

 

  import java.net.Socket;

  public class SocketClient {

   public static void main(String[] args) {

   try {

   // new Socket连接一台机器

   Socket client = new Socket("192.168.150.11",9090);

   client.setSendBufferSize(20); // 设置发送缓冲区

   client.setTcpNoDelay(true);

   OutputStream out = client.getOutputStream(); // 得到输出流

   InputStream in = System.in;

   BufferedReader reader = new BufferedReader(new InputStreamReader(in));

   while(true){

   String line = reader.readLine();

   if(line != null ){

   byte[] bb = line.getBytes();

   // 把手动输入的数据输出到字节数组,但是注意没有flush

   for (byte b : bb) {

   out.write(b);

   } catch (IOException e) {

   e.printStackTrace();

  

 

  准备测试:
 

  先使用netstat -natp查看现有的socket
 

  开启另一个窗口,监听网络连接的数据包
 

  开启新的窗口启动服务端代码
 

  
 

  可以看到开启一个9090端口,然后阻塞住了,等待输入

  然后切换窗口查看socket
 

  
 

  这个服务端开启了一个端口是监听状态

  然后再开一个窗口启动客户端
 

  
 

  可以看到客户端启动了,等待用户输入

  这个时候别急着操作,切换到监听网络连接的数据包,可以看到三次握手已经建立
 

  建立三次握手以后,再来查看一下socket,发现9090端口建立起了连接,有了相应的四元组。
 

  但是没有分配给所对应的进程使用,Recv接收数据为0,Send发送数据也为0
 

  然后客户端发送了1111,四个1,回车之后发送了过去
 

  查看连接数据包,可以看到有交互的
 

  再查看socket连接,可以看到还是没有显示分配给哪个进程使用的,但是内核里已经接受到了4个字节
 

  然后查看这个7932(连接的监听状态端口),虽然上面内核里已经建立连接,得到了四元组,并且接受到了客户端的数据,虽然没有分配给对于的进程使用,但是程序还是监听状态的
 

  接下来让连接分给对应的程序:
 

  服务端点击回车确认,服务端就结束阻塞,代码就执行到了Socket client = server.accept();,调用了.accept()方法后,分配了一个进程,并且接受了4个字节,也读到了接受的字符,四个1
 

  这个时候再看socket连接,发现已经出现分配给了7932端口
 

  然后查看这个7932的网络连接的文件描述符已经得到了
 

  TCP是面向连接的、可靠的传输协议,要经过三次握手,然后内核开辟资源(客户端执行server.accept()后)
 

  
 

  当内核分配了四元组以后,程序如果想要使用这个连接,会有一个网络通信的文件描述符,如图中FD3,如果有个程序使用另外一个连接,就会有另一个文件描述符,当然可以使用FD3,因为是不同的连接进程,相互是隔离的。

  至于端口号被占用的问题,比如图中服务端0.0.0.0: 0端口,和客户端的0.0.0.0: 80端口进行了listen连接,如果这个时候客户又要进行另一个和服务端的连接,但是有两个80端口,四元组出现了两个一样的,没有了唯一性,所以第二个连接不知道分给哪个80端口进行连接了,就冲突了,所以报错。

  程序应用要使用连接时候产生的这个文件描述符,是个抽象的,指向了内核里的socket连接,每个连接有绑定个buffer,缓冲区可以读写两个方向。
 

  如果有另外一个客户端连接过来服务端应用,那就是另外一个连接了。
 

  客户端也是一个应用,所以也是有内核的,一样也有三次握手,和服务端是一样的,客户端也有自己连接的文件描述符。
 

  BACK_LOG 参数

  先把服务端代码跑起来,BACK_LOG 参数设置是2
 

  查看socket,9090端口是监听状态
 

  启动客户端
 

  和上面一样,发现了内核级的三次握手,服务端程序是阻塞的
 

  再启动一个客户端
 

  然后查看socket,有2个连接了,都是在内核级完成了连接,还没有具体的分配给某个进程
 

  这个时候如果再启动新的客户端进行连接,是不行的,服务端只接受2个

  MTU 和 MSS

  启动服务端
 

  开另一个窗口连接服务端端口
 

  然后不停的一直发送数据
 

  然后查看socket,发现这个连接一直是1920,涨不上去了
 

  客户端最后再发送一些1
 

  然后查看socket其实还是1920,这个时候在服务端程序回车,不再阻塞
 

  然后就会读到一些数据,但是发现最后的那些个1111没有读到,说明只接收到了前面的,后面超过1920大小的数据都给丢失了
 

  发送数据包可以大于缓冲区的配置调优

  启动服务端
 

  修改客户端配置,在下面的代码中虽然是写的一个一个字节发送的,但这个配置可以调优成发送一个数据包直接给服务端
 

  然后编译,运行
 

  然后服务端直接回车,不再阻塞
 

  然后客户端发送数据
 

  然后查看服务端接受数据
 

  
 

  数据明显超过了客户端设置的20缓冲区大小,说明一个数据包是可以超过缓冲区的大小

  接下来,重新测试,把客户端的配置setTcpNoDelay()为true,表示缓冲区满了就发送,不用攒着了
 

  然后重新编译,启动,发送数据给服务端
 

  服务端可以看到效果,确实发现客户端发送数据没有攒着,有数据就立马发送了
 

  以上就是3、 网络IO:Socket编程BIO和TCP参数(socket网络编程流程图)的详细内容,想要了解更多 3、 网络IO:Socket编程BIO和TCP参数的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: