一. 网络程序运行过程中的常见异常及处理

第1个异常是 java.net.BindException:Address already in use: JVM_Bind。

该异常发生在服务器端进行new ServerSocket(port)(port是一个0,65536的整型值)操作时。异常的原因是以为与port一样的一个端口已经被启动,并进行监 听。此时用netstat –an命令,可以看到一个Listending状态的端口。只需要找一个没有被占用的端口就能解决这个问题。

第2个异常是java.net.ConnectException: Connection refused: connect。

该异常发生在客户端进行 new Socket(ip, port)操作时,该异常发生的原因是或者具有ip地址的机器不能找到(也就是说从当前机器不存在到指定ip路由),或者是该ip存在,但找不到指定的端 口进行监听。出现该问题,首先检查客户端的ip和port是否写错了,如果正确则从客户端ping一下服务器看是否能ping通,如果能ping通(服务 服务器端把ping禁掉则需要另外的办法),则看在服务器端的监听指定端口的程序是否启动,这个肯定能解决这个问题。

第3个异常是java.net.SocketException: Socket is closed,

该异常在客户端和服务器均可能发生。异常的原因是 己方主动关闭了连接后(调用了Socket的close方法)再对网络连接进行读写操作。

第4个异常是java.net.SocketException: (Connection reset或者Connect reset by peer:Socket write error)。

该异常在客户端和服务器端均有可能发生,引起该异常的原因有两个,第一个就是如果一端的Socket被关闭 (或主动关闭或者因为异常退出而引起的关闭),另一端仍发送数据,发送的第一个数据包引发该异常(Connect reset by peer)。另一个是一端退出,但退出时并未关闭该连接,另一端如果在从连接中读数据则抛出该异常 (Connection reset)。简单的说就是在连接断开后的读和写操作引起的。

第5个异常是java.net.SocketException: Broken pipe。

该异常在客户端和服务器均有可能发生。在第4个异常的第一种情况中(也就是抛出 SocketExcepton:Connect reset by peer:Socket write error后),如果再继续写数据则抛出该异常。前两个异常的解决方法是首先确保程序退出前关闭所有的网络连接,其次是要检测对方的关闭连接操作,发现对 方关闭连接后自己也要关闭该连接。

二.编写网络程序时需 要注意的问题 

第1个问题是要正确区分长、短连接。所谓的长连接是一经建立就永久保持。短连接就是在以下场景下,准备数据—>建立连接— >发送数据—>关闭连接。很多的程序员写了多年的网络程序,居然不知道什么是长连接,什么是短连接。

第2个问题是对长连接的维护。所谓的维护包括两个方面,首先是检测对方的主动断连(既调用 Socket的close方法),其次是检测对方的宕机、异常退出及网络不通。这是一个健壮的通信程序必须具备的。检测对方的主动断连很简单,主要一方主 动断连,另一方如果在进行读操作,则此时的返回值只-1,一旦检测到对方断连,则应该主动关闭己方的连接(调用Socket的close方法)。而检测对 方的宕机、异常退出及网络不通常用方法是用“心跳”,也就是双方周期性的发送数据给对方,同时也从对方接收“心跳”,如果连续几个周期都没有收到对方心
跳,则可以判断对方或者宕机或者异常推出或者网络不通,此时也需要主动关闭己方连接,如果是客户端可在延迟一定时间后重新发起连接。虽然Socket有一 个keep alive选项来维护连接,如果用该选项,一般需要两个小时才能发现对方的宕机、异常退出及网络不通。

第3个问题是处理效率问题。不管是客户端还是服务器,如果是长连接一个程序至少需要两个线程,一个用于接 收数据,一个用于发送心跳,写数据不需要专门的线程,当然另外还需要一类线程(俗称Worker线程)用于进行消息的处理,也就是说接收线程仅仅负责接收 数据,然后再分发给Worker进行数据的处理。如果是短连接,则不需要发送心跳的线程,如果是服务器还需要一个专门的线程负责进行连接请求的监听。这些 是一个通信程序的整体要求,具体怎么设计你的程序,就看你自己的设计水平了。

-------------------------------------------------------------
3 长连接和短连接的问题.华为的却在说明文件里面提了一句长连接,其他的细节问题,比如长连 接的保持,长连接的出错问题,都没有提到,开发的时候按短连接处理了.后来经过几翻周折,找到华为的技术人员.直接交流,问清了一些技术细节的问题,去除 了一些疑惑,然后改代码. 

4 和zxccss的交互.因为开始短连接的话,不用考虑到线程的同步问题.现在做长连接,如果多个线程访问同一个 socket,这个全局的socket就需要进行资源保护,因为算法库是由zxccss的线程调用的,他的线程的运行机制我也不熟悉,发了邮件给 zxccss以前的作者李伟华,在深圳的李伟华虽然现在不做这个东西了,但是他很热情的帮我联系到了现在负责这个东西的同事,这里对他赞一个.后来问清了 zxccss的线程机制 ,用信号量的方法对全局长连接socket进行保护.修改代码. 

5 和华为的交流问题,我不知道华为的态度是什么,反 正感觉是他们对这个项目不是很重视,投入的人力精力都不够,还好在各位同事的帮忙督促下,他们也在一点一点的做东西,其实中兴华为人家外面的人和称"中华 为兴",如果这个东西他们合作一些,至少可以在一半的时间内做好。我们做底层开发的还能做什么?不过是把手头的工作做好罢了. 

6 这周和用服的 三个同事同吃同住同劳动,感觉到这这边的辛苦,没有一天是2点前岁的,早上9点过又去了.通过和他们交流,我越来越感觉到个东西.大家都觉得现在的版本管 理啊,项目升级啊有诸多的问题.我没有接触,感觉不深,但是这次这个zxcomsvr搞的我是很是郁闷的.从开发的角度来说,除了平时大家负责一点,多想 想自己的代码,少出点bug外,我们这边能不能建立一个bug数据库这样类似的东西,把开发,现场的bug想办法放到数据库中,以后遇到了,好去重现,或 去修改,或者大家把自己遇到的问题,解决方法都放到里面去,做个有效的搜索机制供别人使用,这自己虽然花的时间多了一点点,但是能为后来的人节省很多的时
间,这是我的一点不成熟的想法,只有个大概的概念。不过这种东西如果推广,应该可以受到大家,特别是前方用服的欢迎的。 


-----------------------------------------------------


------------------------------------------------------

Socket 通信(发送&接收)

最近工作需要,做了一点Socket通讯的东西,积累一点经验,与大家共分享
其中通过短连接方式接收Socket返回消息,死循环,分别判断接收和超时,来确定连接连接状况
通过字节流的形式获取socket返回消息,主要是因为通过readline的方式,在我们系统通讯中存在异常。
具体客户端代码如下:


import java.net.*;

import java.io.*;
import org.apache.log4j.Logger;

public class SocketClient {
    static Logger log = Logger.getLogger(SocketClient.class.getName());   //日志记录信息

    private String hostName;

    private int portNum;

    private int delaySecond;    // 发文接收返回报文延时
    public SocketClient() {

        this.hostName = "192.168.0.1";

        this.portNum = 7000;

        this.delaySecond = 50000;

        pFileOp = null;

    }
    private Socket getSocket() {

        Socket socket = null;

        try {

            socket = new Socket(hostName, portNum);

        } catch (UnknownHostException e) {

            System.out.println("-->未知的主机名:" + hostName + "    异常");

        } catch (IOException e) {

            System.out.println("-hostName=" + hostName + "   portNum="

                    + portNum + "---->IO异常错误" + e.getMessage());

        }

        return socket;

    }

    public String sendMessage(String strMessage) {

        String str = "";

        String serverString = "";

        Socket socket;

        try {

            socket = getSocket();

            // socket.setKeepAlive(true);

            if (socket == null) { // 未能得到指定的Socket对象,Socket通讯为空

                return "0001";

            }

            PrintWriter out = new PrintWriter(socket.getOutputStream());

            //log.info("---->发送报文="+strMessage);

            out.println(strMessage);

            out.flush();

            BufferedReader in = new BufferedReader(new InputStreamReader(

                    socket.getInputStream()));

            long sendTime = System.currentTimeMillis();

            long receiveTime = System.currentTimeMillis();

            boolean received = false; // 成功接收报文

            boolean delayTooLong = false;

            serverString = null;

            while (!received && !delayTooLong) {

                if (socket.getInputStream().available() > 0) {

                    // serverString = in.readLine();

                    char tagChar[];

                    tagChar = new char[1024];

                    int len;

                    String temp;

                    String rev = "";

                    if ((len = in.read(tagChar)) != -1) {

                        temp = new String(tagChar, 0, len);

                        rev += temp;

                        temp = null;

                    }

                    serverString = rev;

                }

                receiveTime = System.currentTimeMillis();

                if (serverString != null)

                    received = true;                                        // 字符串不为空,接收成功

                if ((receiveTime - sendTime) > delaySecond)

                    delayTooLong = true;                                    // 接收等待时间过长,超时

            }

            in.close();

            out.close();
            str=serverString;

            if (delayTooLong) str="2190";                                   //超时标志为真,返回超时码

            if (!received) str ="2190";

            socket.close();

        } catch (UnknownHostException e) {

            log.error("---->出现未知主机错误! 主机信息=" + this.hostName + "   端口号="

                    + this.portNum + "  出错信息=" + e.getMessage());

            str = "2191";

            // System.exit(1);

        } catch (IOException e) {

            log.error("---->出现IO异常! 主机信息=" + this.hostName + "   端口号="

                    + this.portNum + "  出错信息=" + e.getMessage());

            e.printStackTrace();

            str = "2191";

        } catch (Exception e) {

            str="2177";

            log.error("---->出现未知异常" + e.getMessage());

        } finally {

            socket = null;

            str.trim();

            //log.info("--->返回的socket通讯字符串="+str);

            return str;

        }

    }

   
}


-------------------------------------------------------


Socket客户端与服务器建立连接A,连接B  

A,B 连接得到服务器确认后  

A承担工作,发送接受命令与服务端通讯,同时每隔6秒发送心跳包到服务端  

B承担工作,接受服务端返回心跳 包,30秒接受不到心跳包,判断出连接断开 

网上很多写自定义心跳实现长连接,却没有Java方面客户端的代码实现

JAVA网络编程Socket常见问题 【长连接专题】的更多相关文章

  1. java网络编程socket\server\TCP笔记(转)

    java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅     1 TCP的开销 a ...

  2. java网络编程socket解析

    转载:http://www.blogjava.net/landon/archive/2013/07/02/401137.html Java网络编程精解笔记2:Socket详解 Socket用法详解 在 ...

  3. Java网络编程——Socket

    网络是连接不同计算机的媒介,不同的计算机依靠网络来互相通信,即传递数据. Java中与网络编程相关的部分主要是Socket(套接字),它作为一种抽象的结构,实现了与通信相关的各类方法,构成一套完整的通 ...

  4. day05 Java网络编程socket 与多线程

    java网络编程 java.net.Socket Socket(套接字)封装了TCP协议的通讯细节,是的我们使用它可以与服务端建立网络链接,并通过 它获取两个流(一个输入一个输出),然后使用这两个流的 ...

  5. java网络编程Socket通信详解

    Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket.像大家熟悉的QQ.MSN都使用了Socket相关的技术. ...

  6. java如何实现Socket的长连接和短连接

    讨论Socket必讨论长连接和短连接 一.长连接和短连接的概念 1.长连接与短连接的概念:前者是整个通讯过程,客户端和服务端只用一个Socket对象,长期保持Socket的连接:后者是每次请求,都新建 ...

  7. java网络编程——socket实现简单的CS会话

    还记得当年学计网课时用python实现一个简单的CS会话功能,这也是学习socket网络编程的第一步,现改用java重新实现,以此记录. 客户端 import java.io.*; import ja ...

  8. java 网络编程Socket

    TCP: 通过TCP协议传输,得到的是一个顺序的无差错的数据流. 发送方和接收方的成对的两个socket之间必须建立连接, 以便在TCP协议的基础上进行通信,当一个socket(通常都是server ...

  9. Java网络编程Socket通信

        TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议     UDP (User Datagram Proto ...

随机推荐

  1. 01-编写CMS注意事项

    原文:01-编写CMS注意事项 1.将ThinkPHP核心文件放在项目目录,将下载的扩展包放在在ThinkPHP目录下的Extend文件夹中 2.设置整个项目的编码为utf-8 3.创建Public公 ...

  2. hdu 2594 Simpsons’ Hidden Talents 【KMP】

    题目链接:http://acm.acmcoder.com/showproblem.php?pid=2594 题意:求最长的串 同一时候是s1的前缀又是s2的后缀.输出子串和长度. 思路:kmp 代码: ...

  3. hdu 5090 Game with Pearls

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5090 题意:n个数,k,给n个数加上k的正倍数或者不加,问最后能不能凑成1 到 n的序列 题目分类:暴 ...

  4. How-To: add EPEL repository to Centos 6.x is Easy!

    How-To: add EPEL repository to Centos 6.x is Easy! | ITek Blog How-To: add EPEL repository to Centos ...

  5. Delphi过程函数传递参数的八种方式

    今天一同事问我为什么有些过程函数里面有Var而有些没有,不解,遂到网上百度,得解.快哉,快哉. 在Delphi过程.函数中传递参数几个修饰符为Const.Var.Out.另一种不加修饰符的为默认按值传 ...

  6. Linux创建修改删除用户和组

    Linux 创建修改删除用户和组 介绍 在日常的维护过程中创建用户操作用的相对会多一些,但是在这个过程中涉及到的知识点就不单单就是useradd了,接下来就来详细了解账号管理的相关信息. 用户信息 先 ...

  7. cmake编译时遇到的问题解决

    编译cmake首先须要gcc环境,能够运行 gcc --version命令看看. 假设没有,能够使用yum或从cd中进行安装,此处是在虚拟机中从cd中进行安装.将cd链接到虚拟机都会吧,此处略去,.. ...

  8. JMX操作ActiveMQ(1)

    我们知道ActiveMQ broker的管理接口是通过JMX方式提供的. 一个简单的访问方式就是通过jconsole,输入 service:jmx:rmi:///jndi/rmi://localhos ...

  9. Do you master on array in C ?

    Do you master on array in C ? 因为新标准C99的支持变长数组, 差点儿C的标准特性就是看着gcc来的(Linux 内核严重依赖GCC) int mani() { cons ...

  10. API拾遗录之Fragment

    Fragment必须内嵌到activity中,它不能单独使用,并且它的生命周期受到activity生命周期的制约——当activity暂停时,所有的fragment暂停,当activity停止时,所有 ...