我在理解 Java如何处理Windows和 Linux上的套接字方面遇到了很多麻烦 – 特别是当其中一方(客户端或服务器)突然关闭连接时.

我编写了以下非常简单的Server和Client类,以使我的观点变得简单,客观,并且易于理解:

SimpleClient.java:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import java.net.socket;

public class SimpleClient {

    public static void main(String args[]) {
        try {
            Socket client_socket = new Socket("127.0.0.1",9009);

            // Used to read from a terminal input:
            BufferedReader br = new BufferedReader(new InputStreamReader(system.in));

            // Used for client/server communication:
            BufferedReader in = new BufferedReader(new InputStreamReader(client_socket.getInputStream()));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client_socket.getoutputStream()));

            while(true) {
                System.out.print("Command: ");
                String msg = br.readLine();

                // Send:
                out.write(msg);
                out.newLine();
                out.flush();

                // Receive:
                int ifirst_char;
                char first_char;

                if((ifirst_char = in.read()) == -1) {  // Server Closed
                    System.out.println("Server was closed on the other side.");

                    break;
                }

                first_char = (char) ifirst_char;

                msg = String.valueOf(first_char);

                msg += in.readLine();

                // Shows the message received from the server on the screen:
                System.out.println(msg);
            }
        }
        catch(Exception e) {
            e.printstacktrace();
        }

    }
}

SimpleServer.java:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import java.net.ServerSocket;
import java.net.socket;

public class SimpleServer {

    public static void main(String args[]) {
        try {
            ServerSocket server_socket = new ServerSocket(9009);

            Socket client_socket = server_socket.accept();

            while(true) {
                BufferedReader in = new BufferedReader(new InputStreamReader(client_socket.getInputStream()));
                BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client_socket.getoutputStream()));

                // Receive:
                int ifirst_char;
                char first_char;

                if((ifirst_char = in.read()) == -1) {  // Client Closed
                    System.out.println("Client was closed on the other side.");

                    break;
                }

                first_char = (char) ifirst_char;

                String msg = msg = String.valueOf(first_char);

                msg += in.readLine();

                msg = "Server Received: " + msg;

                // Send:
                out.write(msg);
                out.newLine();
                out.flush();
            }
        }
        catch(Exception e) {
            e.printstacktrace();
        }
    }
}

当然,我可以实现一个代码来正确关闭客户端或服务器,但正如我所说,目标是模拟任何一方的突然关闭,不能发送或接收“断开代码”.这就是我创建这两个非常简单的类的原因.
在Linux上,它运行得很好:

$java SimpleClient 
Command: echo
Server Received: echo
Command: test
Server Received: test
Command: (server Now was closed on the other side)
Server was closed on the other side.
$

但是在Windows上:

C:\simplesocket>java SimpleClient
Command: echo
Server Received: echo
Command: test
Server Received: test
Command: (server Now was closed on the other side)
java.net.socketException: Connection reset by peer: socket write error
        at java.net.socketoutputStream.socketWrite0(Native Method)
        at java.net.socketoutputStream.socketWrite(UnkNown Source)
        at java.net.socketoutputStream.write(UnkNown Source)
        at sun.nio.cs.StreamEncoder.writeBytes(UnkNown Source)
        at sun.nio.cs.StreamEncoder.implFlushBuffer(UnkNown Source)
        at sun.nio.cs.StreamEncoder.implFlush(UnkNown Source)
        at sun.nio.cs.StreamEncoder.flush(UnkNown Source)
        at java.io.OutputStreamWriter.flush(UnkNown Source)
        at java.io.BufferedWriter.flush(UnkNown Source)
        at SimpleClient.main(SimpleClient.java:32)

假设我尝试通过修改SimpleClient.java上的以下行来忽略此异常:

// Send:
try {
    out.write(msg);
    out.newLine();
    out.flush();
    }
catch(Exception e) {}

抛出另一个异常:

C:\simplesocket>java SimpleClient
Command: echo
Server Received: echo
Command: test
Server Received: test
Command: (server Now was closed on the other side)
java.net.socketException: Connection reset
        at java.net.socketInputStream.read(UnkNown Source)
        at java.net.socketInputStream.read(UnkNown Source)
        at sun.nio.cs.StreamDecoder.readBytes(UnkNown Source)
        at sun.nio.cs.StreamDecoder.implRead(UnkNown Source)
        at sun.nio.cs.StreamDecoder.read(UnkNown Source)
        at java.io.InputStreamReader.read(UnkNown Source)
        at java.io.BufferedReader.fill(UnkNown Source)
        at java.io.BufferedReader.read(UnkNown Source)
        at SimpleClient.main(SimpleClient.java:42)

我不知道代码上的相应行是否会在这些异常上指出,但是第一个抛出out.flush()而第二个抛出on.read().
所以基本上,正如你在Linux上看到的那样,即使在突然关闭服务器之后:
1.当我尝试发送数据时,它不会抛出异常.
2.更重要的是,当我尝试接收它时,第一个字符为“-1”并正确接收.

在Windows上,它在发送时抛出异常,更重要的是在接收时抛出异常 – 当调用read()方法时 – 我无法获得“流末尾”(-1)代码.

这引出了一些问题:
1.为什么Windows x Linux上有这么大的差异?为什么在Linux上这些例外不会在Windows上被抛出?
2.具有所有跨平台特性的Java是否应该尽量减少在两个系统中运行的差异? (顺便说一句,我在两者上使用JDK 7)
3.有没有办法改变突然关闭的代码并让它在Windows上更像“Linux-like”,而不抛出所有这些异常并在我的in.read()上得到-1?
4.如果没有,建议使用任何外部API?

我试图在网上搜索这个特定主题几个小时,但没有成功.

我也尝试了许多解决方案,比如在客户端的client_socket中调用isConnected(),isBound(),isClosed()等方法,但没有成功.即使在关闭服务器之后,他们总是说有一个活动连接并且没有问题.希望有人会花时间回答这些问题中的至少一个问题.

对于任何答案,您都会提前致以最诚挚的谢意.

你的代码没有任何关闭,所以我假设你实际上意味着一个端点进程被停止,也就是被杀死.

Unix socket sd是“只是”fd的,当Unix进程结束而没有关闭fd时,包括JVM停止的情况
并且你没有调用close(或shutdown-WR),操作系统关闭了fd,对于TCP套接字来说这是关键的(至少尝试)
正常的也就是优雅的关闭:与FIN-WAIT和TIME-WAIT的FIN / ACK交换.我知道制作Unix套接字的唯一方法
在TCP级别(RST)执行graceless close是在关闭之前将linger设置为0(显式或退出).
中间盒强行破坏与RST的连接也是可能的并且并不罕见;例如,我见过防火墙
RST你15分钟后不活动.我也更少见过伪造FIN的中间盒,或试图做错但做错了.

Windows套接字(WinSock)是与文件不同的API.如果Windows进程结束而没有调用closesocket(类似于
但是,从关闭)或至少关闭-WW,Winsock做RST.要在Windows上优雅地关闭(FIN)(通过JVM)
必须打电话给其中一个. JVM可能跟踪java.net.sockets(但不是JNI中的任何内容)并在JVM出口处为您执行此操作,但是
它没有;你可以要求增强.如果你用TaskMgr或类似的东西外部杀死它,那么即使这样也行不通
如果遇到JVM故障可能无法正常工作:JVM尝试捕获故障并提供一个小型工具,这将是一个尝试的地方
清理套接字,但如果有一个JVM错误,它可能会再次失败 – 而且IME大多数JVM错误都是由于JVM错误造成的.

如果它足以处理代码错误(泄漏)和信号而不是JVM错误和失败,那么你可以只是Socket的子类
因此,如果force(graceful)关闭.finalize并在退出时使用Runtime.addShutdownHook,并使用它.

在Unix或Windows套接字中,收到的FIN被视为文件结束,就像任何其他文件一样,例如磁盘文件.
收到的RST作为错误[WSA] ECONNRESET返回给JVM,这引发了异常.隐藏这个并不好
差异,因为对于你以外的应用程序,它可能很重要 – 足以使某些协议不得不改变
防止伪FIN成为安全漏洞,特别是SSLv2和HTTP / 0.9.

如果您还考虑对等系统出现故障(不仅仅是JVM)或网络某些部分出现故障的情况,
或者您的网络接口出现故障,您可以获得的异常变化更大.恕我直言,不要试图处理那些,
只需报告您所看到的内容,让sysadmins和netadmins对其进行排序.我见过程序员得到Exception X的情况
由于问题P在实验室条件下编码而已,但在现实世界中,异常X发生了很大的不同
原因和“有用”处理实际上使解决问题变得更加困难.

旁白:服务器应该在不在while(true)do-a-line循环内部之前创建BufferedReader;如果您曾经/希望一次发送多行的客户端,则显示的代码将丢失数据.如果first_char == – 1,则不需要该头发,否则转换为String;只需使用in.readLine,它就会完全返回null初始in.read返回-1的情况相同,这是(TCP)Socket在收到FIN时的情况.相反,应检查来自system.in的客户端readLine;如果有人输入^ Z或^ D或任何你会得到NPE.

Windows和Linux之间Java套接字的差异 – 如何处理它们?的更多相关文章

  1. 配置iOS VoIP应用程序以在睡眠/后台模式下运行

    我正在开发基于VoIP的iOS(7.1)应用程序.它的底层套接字编程是用C而不是客观C编写的.应用程序在前台运行良好,但在进入睡眠/后台模式时,它无法从服务器接收任何通信.根据apple文档,我们必须为VoIP使用配置一个appsocket.我无法弄清楚如何配置C套接字.目的是在睡眠模式下运行应用程序,直到它被杀死.从SO中尝试了几个链接甚至几个链接,但由于我是新手,我希望这个配置有一步一步的过程.[注意:在某个地方我发现了CoreFoudation框架,我是否需要使用它?

  2. 我应该使用哪个高级API来管理iOS上的UDP套接字?

    在“NetworkProgrammingTopicsConceptualGuide”的“UsingSocketsandStreams”一章中,Apple说:Note:POSIXnetworkingdoesnotactivatethecellularradiooniOS.Forthisreason,thePOSIXnetworkingAPIisgenerallydiscouragediniOS.同样

  3. 为什么这个OpenGL ES 2.0着色器不能在iOS上使用我的VBO?

    如果有人能够了解这里出了什么问题,也许是对gl命令或其他一些不兼容的命令序列的错误排序,我将非常感谢你的帮助.尽管谷歌在“OpenGLES2.0编程指南”中进行了大量研究和研究,但我一直试图让这段代码整天都没有成功.我正在尝试在iPhone上的OpenGLES2.0中使用顶点缓冲区对象和自定义着色器.我试图交错来自以下类型的一系列自定义结构的顶点数据:位置,半径和颜色字节分别考虑顶点位置,点大小和

  4. iOS:使用CFStreamCreatePairWithSocketToHost的套接字网络基础

    >每次要发送新数据对象时,是否设置了新套接字?>我是否必须重置outputStream并发送更多数据.码大部分代码来自CocoaStreamsDocumentation:响应:请注意,在发送数据后,outputStream流将关闭.我尝试在[selfsendString:@“AnotherTest”]之前重新启动outputStream.我也试过了idz的回答.根据文档,我相信len:0的发送缓冲区是我的问题.IfthedelegatereceivesanNsstreamEventHasspaceAvai

  5. ios – AFNetworking / NSURLConnection接收NSPOSIXErrorDomain代码= 9“操作无法完成.坏文件描述符“

    有人在他们的AFNetworking操作中遇到这个错误吗?此外,如果我真的想要,如何故意关闭这个文件描述符?

  6. ios – 将两个字符串转换为一组布尔值的快速方法是什么?

    我有一个长字符串,我想转换为一个布尔值数组.而且它需要很多次,很快.我天真的尝试是这样的:但这比我想要的要慢很多.我的剖析告诉我,地图是减速的地方,但我不知道我能做多么简单.我觉得如果没有Swift’s/ObjC的开销,这样做会很快.在C中,我认为这是一个简单的循环,其中一个字节的内存与一个常量进行比较,但我不知道我应该看的是什么函数或语法.有更好的办法吗?

  7. 在iOS上默认是char签名还是未签名?

    默认情况下,iOS上是否签名或未签名?(我认为这将是一个很好的回答问题,但奇怪的是谷歌没有任何用处!

  8. ios – 如何创建一个本机显示浮动窗口的ANE

    如何在Xcode中创建本机窗口并将其与MobileFlex应用程序集成.本机窗口应该与StageWebView组件类似,其中本机内容浮动在Flex应用程序的其余部分的矩形区域中.解决方法作为一名灵活的程序员,这是一个繁琐的过程,花了我几个星期才弄明白.希望这将有助于其他一些Xcode新手.首先,您必须对Objective-C和Xcode有基本的了解.您应该能够创建一个简单的HelloWorldXc

  9. iOS:无法完成套接字错误操作断管

    我每隔一段时间就会从iOS应用程序向套接字服务器发送一些数据.它正确地发送数据.我看到一个奇怪的问题,如果iOS设备屏幕在从iOS应用程序发送数据时关闭,然后如果我在设备上屏幕,然后我收到以下错误,应用程序已经与套接字断开连接或有时它会崩溃应用程序:当设备屏幕关闭时,我的iOS应用程序停止向套接字发送数据.然后再打开屏幕,插座连接断开/断开管道错误.怎么解决?

  10. Swift基础-0003

随机推荐

  1. static – 在页面之间共享数据的最佳实践

    我想知道在UWP的页面之间发送像’selectedItem’等变量的最佳做法是什么?创建一个每个页面都知道的静态全局变量类是一个好主意吗?

  2. .net – 为Windows窗体控件提供百分比宽度/高度

    WindowsForm开发的新手,但在Web开发方面经验丰富.有没有办法为Windows窗体控件指定百分比宽度/高度,以便在用户调整窗口大小时扩展/缩小?当窗口调整大小时,可以编写代码来改变控件的宽度/高度,但我希望有更好的方法,比如在HTML/CSS中.在那儿?

  3. 使用Windows Azure查询表存储数据

    我需要使用特定帐户吗?>将应用程序部署到Azure服务后,如何查询数据?GoogleAppEngine有一个数据查看器/查询工具,Azure有类似的东西吗?>您可以看到的sqlExpressintance仅在开发结构中,并且一旦您表示没有等效,所以请小心使用它.>您可以尝试使用Linqpad查询表格.看看JamieThomson的thispost.

  4. windows – SetupDiGetClassDevs是否与文档中的设备实例ID一起使用?

    有没有更好的方法可以使用DBT_DEVICEARRIVAL事件中的数据获取设备的更多信息?您似乎必须指定DIGCF_ALLCLASSES标志以查找与给定设备实例ID匹配的所有类,或者指定ClassGuid并使用DIGCF_DEFAULT标志.这对我有用:带输出:

  5. Windows Live ID是OpenID提供商吗?

    不,WindowsLiveID不是OpenID提供商.他们使用专有协议.自从他们的“测试版”期结束以来,他们从未宣布计划继续它.

  6. 如果我在代码中进行了更改,是否需要重新安装Windows服务?

    我写了一个Windows服务并安装它.现在我对代码进行了一些更改并重新构建了解决方案.我还应该重新安装服务吗?不,只需停止它,替换文件,然后重新启动它.

  7. 带有双引号的字符串回显使用Windows批处理输出文件

    我正在尝试使用Windows批处理文件重写配置文件.我循环遍历文件的行并查找我想要用指定的新行替换的行.我有一个’函数’将行写入文件问题是%Text%是一个嵌入双引号的字符串.然后失败了.可能还有其他角色也会导致失败.如何才能使用配置文件中的所有文本?尝试将所有“在文本中替换为^”.^是转义字符,因此“将被视为常规字符你可以尝试以下方法:其他可能导致错误的字符是:

  8. .net – 将控制台应用程序转换为服务?

    我正在寻找不同的优势/劣势,将我们长期使用的控制台应用程序转换为Windows服务.我们为ActiveMQ使用了一个叫做java服务包装器的东西,我相信人们告诉我你可以用它包装任何东西.这并不是说你应该用它包装任何东西;我们遇到了这个问题.控制台应用程序是一个.NET控制台应用程序,默认情况下会将大量信息记录到控制台,尽管这是可配置的.任何推荐?我们应该在VisualStudio中将其重建为服务吗?我使用“-install”/“-uninstall”开关执行此操作.例如,seehere.

  9. windows – 捕获外部程序的STDOUT和STDERR *同时*它正在执行(Ruby)

    哦,我在Windows上:-(实际上,它比我想象的要简单,这看起来很完美:…是的,它适用于Windows!

  10. windows – 当我试图批量打印变量时,为什么我得到“Echo is on”

    我想要执行一个简单的批处理文件脚本:当我在XP中运行时,它给了我预期的输出,但是当我在Vista或Windows7中运行它时,我在尝试打印值时得到“EchoisOn”.以下是程序的输出:摆脱集合表达式中的空格.等号(=)的两侧可以并且应该没有空格BTW:我通常在@echo关闭的情况下启动所有批处理文件,并以@echo结束它们,所以我可以避免将代码与批处理文件的输出混合.它只是使您的批处理文件输出更好,更清洁.

返回
顶部