当前位置: 首页 > 编程笔记 >

Java socket通讯实现过程及问题解决

尹凌龙
2023-03-14
本文向大家介绍Java socket通讯实现过程及问题解决,包括了Java socket通讯实现过程及问题解决的使用技巧和注意事项,需要的朋友参考一下

这篇文章主要介绍了Java socket通讯实现过程及问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

本来是打算验证java socket是不是单线程操作,也就是一次只能处理一个请求,处理完之后才能继续处理下一个请求。但是在其中又发现了许多问题,在编程的时候需要十分注意,今天就拿出来跟大家分享一下。

首先先建立一个服务端代码,运行时也要先启动此程序。

package com.test.some.Socket;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/**
* @Description: socket服务端代码
* @Author:   haoqiangwang3
* @CreateDate: 2020/1/9
*/
public class MySocketServer1 {
  // 服务器监听端口
  private static int port = 8081;

  public static void main(String[] args) throws InterruptedException {
    try {
      //1.得到一个socket服务端
      ServerSocket serverSocket = new ServerSocket(port);
      while (true) {

        // 2.等待socket客户端的请求。accept方法在有连接请求时才会返回
        System.out.println("等待客户端请求。。。");
        Socket socket = serverSocket.accept();
        System.out.println("客户端请求来了。。。");

        // 3.获取socket输入流
        InputStream inputStream = socket.getInputStream();
        /* BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        System.out.println("接收到的请求数据为:" + bufferedReader.readLine());*/
        // 读取请求内容的缓冲区
        byte[] bytes = new byte[1024];
        int length = 0;
        StringBuilder sb = new StringBuilder();
        //获取客户端请求的内容
        while ((length = inputStream.read(bytes)) != -1) {
          sb.append(new String(bytes, 0, length, "utf-8"));
        }
        System.out.println("接收到的请求数据为:" + sb.toString());          
          //Thread.sleep(50000);          // 4.获取socket输出流
        OutputStream outputStream = socket.getOutputStream();
        PrintWriter printWriter = new PrintWriter(outputStream);
        String backStr = "服务端接收到了请求";
        printWriter.write(new String(backStr.getBytes(), "utf-8"));
        printWriter.flush();

        //5.关闭资源
        //bufferedReader.close();
        inputStream.close();
        printWriter.close();
        outputStream.close();
        socket.close();
      }

    } catch (IOException e) {
      System.err.println("socket监听失败!" + e);
    }
  }

}

此代码模拟了正常系统成socket服务端的方式,就是一个无限循环监听我们绑定的端口,当有客户端请求来了之后进行处理。

下面就是客户端请求代码

package com.test.some.Socket;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

/**
* @Description: socket客户端代码
* @Author:   haoqiangwang3
* @CreateDate: 2020/1/9
*/
public class MySocketClient1 {
  //socket请求ip地址
  private static String host = "127.0.0.1";

  //socket请求端口
  private static int port = 8081;

  public static void main(String[] args) {
    try {
      //1.建立一个客户端
      Socket socket = new Socket(host, port);

      //2.得到socket输出流
      OutputStream outputStream = socket.getOutputStream();
      PrintWriter printWriter = new PrintWriter(outputStream);
      String sendStr = "发送数据1";
      //发送数据
      printWriter.write(sendStr);
      printWriter.flush();
      socket.shutdownOutput();

      //3.得到socket输入流
      InputStream inputStream = socket.getInputStream();
      StringBuilder sb = new StringBuilder();
      byte[] bytes = new byte[1024];
      while (inputStream.read(bytes) != -1) {
        sb.append(new String(bytes, "utf-8"));
      }
      System.out.println("接收到的返回数据为:" + sb);

      //4.关闭资源
      printWriter.close();
      outputStream.close();
      inputStream.close();
      socket.close();
    } catch (Exception e) {
      System.err.println("socket请求失败" + e);
    }
  }

}

客户端代码主要就是向服务端发送数据,然后等待服务端的响应,打印出服务端的响应内容。

最终打印结果如下。服务端:

客户端:

首先明确几个概念,下面将会用到。

flush()方法:用于清空缓冲区的数据流,进行流的操作时,数据先被读到内存缓冲区中,然后再用数据写到文件中。

socket.shutdownOutput()方法:他是一种单向关闭流的方法,即关闭客户端的输出流并不会关闭服务端的输出流。通过shutdownOutput()方法只是关闭了输出流,但socket仍然是连接状态,连接并未关闭。

printWriter.close()方法:如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket。

流中的关闭顺序:一般情况下是:先打开的后关闭,后打开的先关闭。另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b,例如处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b。当然完全可以只关闭处理流,不用关闭节点流。处理流关闭的时候,会调用其处理的节点流的关闭方法。如果将节点流关闭以后再关闭处理流,会抛出IO异常

下面总结下我遇到的问题。

1.客户端发送数据部分的代码,printWriter.flush(); socket.shutdownOutput(); 这两句代码十分的重要,flush()方法如果不添加的话,服务端接收到的数据将为空,shutdownOutput()方法不添加的话,服务端将一直等待读取客户端的数据,不会往下进行,大家可以自测一下。我自己的理解是flush()的作用是为了把数据从内存中刷新到socket流中,shutdownOutput()方法是告诉服务端,我没有东西要传输了,所以服务端也就会停止等待读取客户端发送的内容,程序就可以继续向下走。

2.打开服务端中的sleep方法,在新建一个客户端,同时开启请求服务端,会发现服务端确实是一个连接一个连接的处理,所以这也是socket性能所在的问题。

3.如果不用字符流读取,客户端发送数据直接用outputStream.write(sendStr.getBytes());,可以发现此时不用调用flush()方法,但是socket.shutdownOutput()依然需要。这是因为直接读取到socket的输出流,并没有读到内存中。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 问题内容: 这可能太局限了,但我希望有人可以帮助我正确阐明我的问题。 因此,我们有一个前端Web服务器,该服务器使用CORBA与后端应用程序服务器进行通信。我曾被要求将后端应用程序移植到LINUX盒中。但是,为了测试它,我试图将前端Web服务器指向LINUX后端。 我们正在使用omniORB-4.1.4,这是获取后端系统实例的方法: 当前端和后端都在SUN / Solaris机器上运行时,似乎可以

  • 本文向大家介绍通过实例了解JavaBean开发及使用过程解析,包括了通过实例了解JavaBean开发及使用过程解析的使用技巧和注意事项,需要的朋友参考一下 一、JavaBean简介 JavaBean是使用Java语言开发的一个可重用的组件,在JSP的开发中可以使用JavaBean减少重复代码,使整个JSP代码的开发更简洁。JSP搭配JavaBean来使用,有以下的优点: 1.可将HTML和Java

  • 本文向大家介绍浅谈Java多线程实现及同步互斥通讯,包括了浅谈Java多线程实现及同步互斥通讯的使用技巧和注意事项,需要的朋友参考一下 Java多线程深入理解本文主要从三个方面了解和掌握多线程: 1. 多线程的实现方式,通过继承Thread类和通过实现Runnable接口的方式以及异同点。 2. 多线程的同步与互斥中synchronized的使用方法。 3. 多线程的通讯中的notify(),no

  • 本文向大家介绍struts2中通过json传值解决乱码问题的实现方法,包括了struts2中通过json传值解决乱码问题的实现方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了struts2中通过json传值解决乱码问题的实现方法。分享给大家供大家参考,具体如下: 在struts2中如果使用json在jsp和java文件传中文值时往往会出现中文乱码访问,解决此问题可以使用以下方法 一、在

  • 本文向大家介绍MySQL redo死锁问题排查及解决过程分析,包括了MySQL redo死锁问题排查及解决过程分析的使用技巧和注意事项,需要的朋友参考一下 问题背景 周一上班,首先向同事了解了一下上周的测试情况,被告知在多实例场景下 MySQL Server hang 住,无法测试下去,原生版本不存在这个问题,而新版本上出现了这个问题,不禁心头一颤,心中不禁感到奇怪,还好现场环境还在,为排查问题提

  • 本文向大家介绍Java实现基于TCP的通讯程序实例解析,包括了Java实现基于TCP的通讯程序实例解析的使用技巧和注意事项,需要的朋友参考一下 Java中的TCP通信程序 TCP可以实现两台计算机之间的数据交互通信的两端,要严格区分客户端与服务端 两端通信时的步骤: 1.服务端程序,需要事先启动,等待客户端连接 2.客户端主动连接服务器端,才能成功通信,服务器端不可以主动链接客户端 在java中两