java socket技术 客户端实现不发送请求给服务端但是一直接收服务端发来的数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java socket技术 客户端实现不发送请求给服务端但是一直接收服务端发来的数据相关的知识,希望对你有一定的参考价值。

服务端使用的是C语言做的,与客户端连通后服务端一直主动推送数据给客户端,客户端使用Java技术实现一直接收数据,该怎么去做?

说点泼冷水的话题
首先确认什么是客户端,什么是服务端。
从用户的角度,可见的、可操作的即是客户端,也就是你这里说的java开发的部分。而不可见的部分就是服务端,也就是你说的C部分。
而从网络开发的角度,发起请求的是客户端,而接收请求的是服务端。这与用户感受有很大区别。
当从java请求C的时候,java是客户端,C 是服务端。而当C主动请求时,则C就变成了客户端,而java 变成了服务端。
所以,从网络开发的角度,java想成为此次通信的服务端,必须长期维护一个端口可用,而C 要访问这个端口。
而java为了能够长期维护一个端口,一般采用socket 方式(其他方式也基本上都是基于socket的),由于java已经封装的很好了,只要new Socket(IP,port) 就可以 获得,同时,由于原来C 是服务器,而如果没有多个服务器同时向java端发送请求的话,基本连线程处理都不需要做的。
参考技术A

    java 可以用apache mina实现Socket客户端。C语言的Socket server网上应该也有很多源码。

    看你的描述,应该类似保持长连接推送计算。

简单描述是:

a 客户端请求服务器端,请求订阅某个推送主题,

b 服务器端给此连接编号,并将该连接保持(使用定期发送心跳报文的方式),将编号与连接保存在内存中。

c 当服务器需要推送消息给客户端时,轮询保持的连接列表,逐一发送消息给客户端。

以下是相关介绍链接:

http://blog.csdn.net/ouyhong123/article/details/39395651


一般做推送服务,对服务器的内存要求比较高,现在流行使用Erlang或Go语言写服务器端。

参考技术B 监听你系统通信所用的端口,有数据就获取显示就可以了。例如你的服务器ip是168.12.1.16,使用的是2000端口号,Socket socket=new Socket("168.12.1.16",2000);
DataOutputStream in=new DataOutputStream(socket.getInputStream());追问

是采用定时去读取信息吗?不发送请求给服务端 服务端会主动把数据推送过来吗?

追答

当然也算是定时读取的一种特殊形式,但是并不需要你自己去实现。他会监听指定的通信端口,当服务器端有数据发送过来是,就能触发相应的事件,自己就可以获取到信息。

本回答被提问者采纳
参考技术C java 你不要关闭socket就好了。

试图重用Java客户端套接字时不成功。

我有一个与第三方控制器通信的软件驱动程序;我有一个用于使用后者的API,但看不到它的源代码,而供应商也不合作,试图改进事情!我的情况如下。

情况是这样的。

为了向控制器发送请求,我发送一个XML包作为HTTP POST的内容给一个servlet,然后servlet给我发送响应。原来的代码,由之前的开发人员实现,使用java.net.Socket可以稳定工作。然而,我们的驱动是这样实现的,每发送一个请求都会创建一个新的套接字,如果驱动忙起来,第三方控制器在套接字处理方面就很难跟上。事实上,他们的支持人员对我说:"你真的需要留出5秒钟的时间。"你真的需要在每个请求之间留出5秒的时间..." 这在商业上根本无法接受。

为了提高性能,我想尝试让我们的套接字端打开,并无限期地重复使用套接字(当然考虑到连接可能会意外掉落,但这是我最不关心的问题,是可以控制的)。然而,无论我看起来做什么,效果都是,如果我使用Comms.getSocket(false),每一个请求都会创建一个新的套接字,一切都能正常工作,但忙的时候会出现瓶颈。如果我使用Comms.getSocket(true),会发生以下情况。

  • 控制器发送了第一个请求
  • 控制器对第一个请求作出回应
  • 控制器被发送第二个请求(可能5秒后)。
  • 控制员从不响应第二个请求或之后的任何事情。
  • postRequest()一直被调用:在前12秒,控制台输出 "Input shut down ? false",但之后,代码不再到达那里,也没有通过bw.write()和bw.flush()调用。

控制器允许HTTP 1.0和1.1,但他们的文档中没有提到keep-alive。我尝试了这两种模式,下面的代码显示我也添加了Keep-Alive头信息,但是作为服务器的控制器,我猜测是忽略了它们 -- 我想我没有办法知道,是吗?在HTTP 1.0模式下,控制器肯定会返回 "Connection: close",但在HTTP 1.1模式下不会这样做。

那么很可能是服务器端坚持 "每个请求一个socket "的方法。

然而,我想知道,在下面的代码中,我是否可能做错了什么(或者遗漏了什么)来实现我想要的东西。

private String postRequest() throws IOException 
    String resp = null;
    String logMsg;
    StringBuilder sb = new StringBuilder();
    StringBuilder sbWrite = new StringBuilder();
    Comms comms = getComms();
    Socket socket = comms.getSocket(true);
    BufferedReader br = comms.getReader();
    BufferedWriter bw = comms.getWriter();
    if (null != socket) 
        System.out.println("Socket closed ? " + socket.isClosed());
        System.out.println("Socket bound ? " + socket.isBound());
        System.out.println("Socket connected ? " + socket.isConnected());

        // Write the request
        sbWrite
            .append("POST /servlet/receiverServlet HTTP/1.1\r\n")
            .append("Host: 192.168.200.100\r\n")
            .append("Connection: Keep-Alive\r\n")
            .append("Keep-Alive: timeout=10\r\n")
            .append("Content-Type: text/xml\r\n")
            .append("Content-Length: " + requestString.length() + "\r\n\r\n")
            .append(requestString);
        System.out.println("Writing:\n" + sbWrite.toString());
        bw.write(sbWrite.toString());
        bw.flush();

        // Read the response
        System.out.println("Input shut down ? " + socket.isInputShutdown());
        String line;
        boolean flag = false;
        while ((line = br.readLine()) != null) 
            System.out.println("Line: <" + line + ">");
            if (flag) sb.append(line);
            if (line.isEmpty()) flag = true;
        
        resp = sb.toString();
    
    else 
        System.out.println("Socket not available");
    
    return resp; // Another method will parse the response

为了方便测试,我用一个额外的Comms助手类和一个叫做getSocket(boolean reuse)的方法来提供套接字,我可以选择总是创建一个新的套接字或者重用Comms为我创建的套接字,如下所示。

public Comms(String ip, int port) 
    this.ip = ip;
    this.port = port;
    initSocket();


private void initSocket() 
    try 
        socket = new Socket(ip, port);
        socket.setKeepAlive(true);
        socket.setPerformancePreferences(1, 0, 0);
        socket.setReuseAddress(true);
        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
        br = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
        System.out.println("@@@ CREATED NEW SOCKET");
    
    catch (UnknownHostException uhe) 
        System.out.println("@@@ UNKNOWN HOST FOR SOCKET");
    
    catch (IOException ioe) 
        System.out.println("@@@ SOCKET I/O EXCEPTION");
    


public BufferedReader getReader()  return br; 

public BufferedWriter getWriter()  return bw; 

public Socket getSocket(boolean reuse) 
    if (! reuse) initSocket();
    return socket;

谁能帮帮我?

答案

如果我们假设keep-alive的工作符合预期,我认为这一行是这样的 while ((line = br.readLine()) != null) 是一个错误的,因为这是一种无限循环。

readline() 返回 null 当没有更多的数据可读时,例如a EOF,或者当serverclient关闭连接时,这将破坏你的重用套接字解决方案,因为一个开放的流永远不会导致一个 nullreadLine() 调用,但会阻塞。

你需要修正关于读取响应的算法(为什么不使用已实现的http客户端?content-length当从body中读取所需的数据量时,通过保持socket的活力进行下一个循环。flagtrue读取数据时,必须知道要读取的是什么数据(考虑到mimecontent-type),除此之外,还要知道数据的长度,所以读取数据时要使用 readLine() 在这里可能不是一个好的做法。

同时确保服务器允许持久化连接,通过检查它是否尊重它,通过响应相同的 connection:keep-alive 头部。

以上是关于java socket技术 客户端实现不发送请求给服务端但是一直接收服务端发来的数据的主要内容,如果未能解决你的问题,请参考以下文章

Java Socket 实现HTTP与HTTPS协议发送POST/GET请求

试图重用Java客户端套接字时不成功。

java socket服务如何监控客户端链接数,如果方便的话请给代码,急求万分感谢!

socket java实现客户端多线程接受消息并发送消息给服务器,并发执行

nodejs-websocket介绍

iOS使用socket实现聊天功能