`

java工具类(获取访问者的IP、Calendar、判断socket是否已经断开及长连接、UDP丢包及无序问题、clob字段、Url请求方式中文乱码

    博客分类:
  • Java
阅读更多

1、获取访问者的IP

public String getIp(HttpServletRequest request) {
		String ip= request.getHeader("X-Forwarded-For");
	    if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
	        ip= request.getHeader("Proxy-Client-IP");
	    if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
	        ip= request.getHeader("WL-Proxy-Client-IP");
	    if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
	        ip= request.getHeader("HTTP_CLIENT_IP");
	    if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
	        ip= request.getHeader("HTTP_X_FORWARDED_FOR");
	    if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
	        ip= request.getRemoteAddr();
	    if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)){
	        try {
	            ip= InetAddress.getLocalHost().getHostAddress();
	        }
	        catch (UnknownHostException e) {
	        	e.printStackTrace();
	        }
	    }
	return ip
}

 

 

/**
     * 获取访问者IP
     * 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。
     * 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割),
     * 如果还不存在则调用Request .getRemoteAddr()。
     * 
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("X-Forwarded-For");
        if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个IP值,第一个为真实IP。
            int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        } else {
            return request.getRemoteAddr();
        }
    }

 2、Calendar

 

public class TestCalendar {

	@Test
	public void test(){
		try {
			Calendar calendar = new GregorianCalendar();//子类实例化
			//获取年、月、日、时、分、秒、毫秒
			System.out.println("年: "+calendar.get(Calendar.YEAR));
			System.out.println("月 "+(calendar.get(Calendar.MONTH)+1));
			System.out.println("日: "+calendar.get(Calendar.DAY_OF_MONTH));
			System.out.println("时: "+calendar.get(Calendar.HOUR_OF_DAY));
			System.out.println("分: "+calendar.get(Calendar.MINUTE));
			System.out.println("秒: "+calendar.get(Calendar.SECOND));
			System.out.println("毫秒 "+calendar.get(Calendar.MILLISECOND));
			
			// 当前月第一天、最后一天
			int currYear = calendar.get(Calendar.YEAR);
			int currMonth = calendar.get(Calendar.MONTH) + 1;
			System.out.print(currYear + "-" + currMonth);
			SimpleDateFormat datef = new SimpleDateFormat("yyyy-MM-dd");
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			Date beginTime = calendar.getTime();
			String sTime = datef.format(beginTime) + " 00:00:00";
			calendar.set(Calendar.DATE, 1);
			calendar.roll(Calendar.DATE, -1);
			Date endTime = calendar.getTime();
			String eTime = datef.format(endTime) + " 23:59:59";
			System.out.println("第一天"+sTime+"最后一天"+eTime);
			
			Calendar cal = Calendar.getInstance(); 
			//指定年月的的第一天、最后一天
			int year = 2015;
			int moth = 3;
			cal.set(Calendar.YEAR,year);
			cal.set(Calendar.MONTH, moth-1);
			//当前月的最后一天   
			cal.set( Calendar.DATE, 1 );
			cal.roll(Calendar.DATE, - 1 );
			Date endTime2=cal.getTime();
			String endTimeStr=datef.format(endTime2)+" 23:59:59";
			//当前月的第一天          
			cal.set(GregorianCalendar.DAY_OF_MONTH, 1); 
			Date beginTime2=cal.getTime();
			String beginTimeStr=datef.format(beginTime2)+" 00:00:00";
			
			System.out.println("指定年月的的第一天"+endTimeStr+"最后一天"+beginTimeStr);
			
			//当前时间的前一天
			SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd:HH");  
			String tmStr = "2015-5-18:00";
			Date d = sdf2.parse(tmStr);  
			System.out.println(d);
			Calendar now = Calendar.getInstance();  
			now.setTime(d);  
			now.set(Calendar.HOUR, now.get(Calendar.HOUR) -1);  
			System.out.println(sdf2.format(now.getTime()));
			
			//最近N天
			SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
			cal.add(Calendar.DATE,-7);
			System.out.println("最近7天"+df2.format(cal.getTime()));
			Calendar ca2 =Calendar.getInstance();
			//最近N个月
			ca2.add(Calendar.MONTH,-1);//最近一个月
			System.out.println("最近一个月"+df2.format(ca2.getTime()));
			Calendar ca3 =Calendar.getInstance();
			//最近N个年
			ca3.add(Calendar.YEAR,-1);//最近一年
			System.out.println("最近一年"+df2.format(ca3.getTime()));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
 3、判断socket是否已经断开
  首先 socket类的方法isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()等,但经过试验并查看相关文档,这些方法都是本地端的状态,无法判断远端是否已经断开连接。然后想到是否可以通过OutputStream发送一段测试数据,如果发送失败就表 示远端已经断开连接,类似ping,但是这样会影响到正常的输出数据,远端无法把正常数据和测试数据分开。 最后又回到socket类,发现有一个方法sendUrgentData,查看文档后得知它会往输出流发送一个字节的数据,只要对方Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节,而SO_OOBINLINE属性默认情况下就是关闭的,所以正是我需要的。 

于是,下面一段代码就可以判断远端是否断开了连接: 

try{ 
      socket.sendUrgentData(0xFF); 
}catch(Exception ex){ 
      reconnect(); 
} 

用ping实现 

package com.csdn.test; 
  import java.io.BufferedReader; 
  import java.io.IOException; 
  import java.io.InputStreamReader; 
  public class test { 
  static BufferedReader bufferedReader; 
  public static void main(String[] args) throws IOException { 
  try { 
  Process process = Runtime.getRuntime().exec("ping 192.168.1.104");//判断是否连接的IP; 
  bufferedReader = new BufferedReader(new InputStreamReader(process 
  .getInputStream())); 
  String connectionStr = ""; 
  while ((connectionStr = bufferedReader.readLine()) != null) { 
  System.out.println(connectionStr); 
  } 
  } catch (IOException e) { 
  e.printStackTrace(); 
  } finally { 
  bufferedReader.close(); 
  } 
  } 
  } 

 
ping的方法有个严重的BUG,就是你只能判断对方是否连接网络,而不能判断客户端是否开启,
在写聊天室时经常要注意客户端异常退出的问题(比如客户直接调用任务管理器结束程序进程), 
其实在通过socket.getoutstream和socket.getinputstream流对客户端发送、接受信息时如果socket没连接上是会抛出异常的,这也就是为什么Java会要求网络编程都要写在try里面,所以只要在catch里面写入客户端退出的处理就行了,没必要专门去想什么方法

socket长连接:

package com.yihongyu.exec.modules.crx.service.impl;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Iterator;
import java.util.Properties;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.yihongyu.exec.modules.crx.manager.CrxNotificationManager;
import com.yihongyu.exec.modules.crx.service.CrxNotificationService;
import com.yihongyu.exec.modules.crx.service.CrxSocketClientService;

@Service
public class CrxSocketClientServiceImpl implements CrxSocketClientService {

	private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);

	@Autowired
	private CrxNotificationService crxNotificationService;

	private Socket socket;
	private Properties props = new Properties();
	private String host;
	private String portStr;

	/** 初始化Socket连接信息 */
	@Override
	@PostConstruct
	public void init() {
		try {
			props.load(new FileInputStream("conf/notifications/crx.properties"));
			host = props.getProperty("crx.host", "192.168.1.225");
			portStr = props.getProperty("crx.port", "8222");
			Integer port = Integer.parseInt(portStr);
			connect(host, port);
		} catch (FileNotFoundException e) {
			LoggerFactory.getLogger(getClass()).error("无法找到Crx服务器配置文件,请检查是否存在文件:conf/notifications/crx.properties!");
		} catch (IOException e) {
			LoggerFactory.getLogger(getClass()).error("装载Crx服务器配置文件失败:conf/notifications/crx.properties!", e);
		}
	}

	/** 创建Socket连接 */
	@Override
	public Boolean connect(String host, int port) {
		try {
			destroy();
			this.socket = new Socket(host, port);
			if (!isOrNotServerClose()) {
				System.out.println("----------------Connection Crx socket success!----------------");
			} else {
				System.out.println("----------------Connection Crx socket fail!----------------");
				LoggerFactory.getLogger(getClass()).error("Connection Crx socket fail!");
			}
			socket.setSoTimeout(60000);
			socket.setKeepAlive(true);
			isServerClose();
			return socket.isConnected();
		} catch (Exception e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
			return false;
		}
	}

	/** 检测服务端Socket是否断开 */
	@Override
	public void isServerClose() {
		executor.schedule(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println("=================sendUrgentData=================");
					socket.sendUrgentData(0XFF);
					isServerClose();
				} catch (IOException e) {// 出现异常,服务端主动断开
					destroy();
					isServerClose();
					LoggerFactory.getLogger(getClass()).error("Crx Server Exception Close!");
					LoggerFactory.getLogger(getClass()).error("重新向服务端发起连接");
					reConnect();// 重新向服务端发起连接
					e.printStackTrace();
				}
			}
		}, 10000, TimeUnit.MILLISECONDS);

	}

	/** 重新创建连接 */
	@Override
	public boolean reConnect() {
		try {
			Integer port = Integer.parseInt(portStr);
			this.socket = new Socket(host, port);
			if (!isOrNotServerClose()) {
				System.out.println("----------------Connection Crx socket success!----------------");
			} else {
				System.out.println("----------------Connection Crx socket fail!----------------");
				LoggerFactory.getLogger(getClass()).error("Connection Crx socket fail!");
			}
			socket.setSoTimeout(60000);
			socket.setKeepAlive(true);
			return true;
		} catch (Exception e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public Boolean isOrNotServerClose() {
		try {
			socket.sendUrgentData(0XFF);
			return false;
		} catch (IOException e) {// 出现异常,服务端主动断开
			LoggerFactory.getLogger(getClass()).error("Crx Server Exception Close!");
			e.printStackTrace();
			return true;
		}
	}

	/** 向Crx服务端发送信息 */
	@Override
	public String process(String contentXml) {
		try {
			System.out.println("Send CrxNotification Xml: " + contentXml);
			if (contentXml != null && contentXml.length() > 0) {
				OutputStream out = this.socket.getOutputStream();
				out.write(contentXml.getBytes("GBK"));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/** 获取Crx服务端返回的信息 */
	@Override
	public String getCrxMsg() throws UnsupportedEncodingException, IOException {
		// 服务端返回的消息状态: 0--发送成功, 1--发送失改, 2--超时
		String crxServerMsg = null;
		InputStream in = socket.getInputStream();
		if (in.available() > 0) {
			byte[] buff = new byte[in.available()];
			in.read(buff);
			crxServerMsg = new String(buff);
		}
		return crxServerMsg;
	}

	/** 关闭socket */
	@Override
	public void destroy() {
		try {
			if (this.socket != null) {
				this.socket.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

 4、UDP丢包及无序问题

在项目中做了个验证程序.

发现客户端连续发来1000个1024字节的包,服务器端出现了丢包现象.

纠其原因,是服务端在还未完全处理掉数据,客户端已经数据发送完毕且关闭了.

 

有没有成熟的解决方案来解决这个问题.

我用过sleep(1),暂时解决这个问题,但是这不是根本解决办法,如果数据量大而多,网络情况不太好的话,还是有可能丢失.

 

你试着用阻塞模式吧...

select...我开始的时候好像也遇到过..不过改为阻塞模式后就没这个问题了...

 

采用回包机制,每个发包必须收到回包后再发下一个

 

UDP丢包是正常现象,因为它是不安全的。

 

丢包的原因我想并不是“服务端在还未完全处理掉数据,客户端已经数据发送完毕且关闭了”,而是服务器端的socket接收缓存满了(udp没有流量控制,因此发送速度比接收速度快,很容易出现这种情况),然后系统就会将后来收到的包丢弃。你可以尝试用setsockopt()将接收缓存(SO_RCVBUF)加大看看能不能解决问题。

 

服务端采用多线程pthread接包处理

UDP是无连接的,面向消息的数据传输协议,与TCP相比,有两个致命的缺点,一是数据包容易丢失,二是数据包无序。

要实现文件的可靠传输,就必须在上层对数据丢包和乱序作特殊处理,必须要有要有丢包重发机制和超时机制。

常见的可靠传输算法有模拟TCP协议,重发请求(ARQ)协议,它又可分为连续ARQ协议、选择重发ARQ协议、滑动窗口协议等等。

如果只是小规模程序,也可以自己实现丢包处理,原理基本上就是给文件分块,每个数据包的头部添加一个唯一标识序号的ID值,当接收的包头部ID不是期望中的ID号,则判定丢包,将丢包ID发回服务端,服务器端接到丢包响应则重发丢失的数据包。

模拟TCP协议也相对简单,3次握手的思想对丢包处理很有帮助。

 

udp是不安全的,如果不加任何控制,不仅会丢失包,还可能收到包的顺序和发送包的顺序不一样。这个必须在自己程序中加以控制才行。

收到包后,要返回一个应答,如果发送端在一定时间内没有收到应答,则要重发。

 

UDP本来存在丢包现象,现在的解决方案暂时考虑双方增加握手.

这样做起来,就是UDP协议里面加上了TCP的实现方法.

程序中采用的是pthread处理,丢包率时大时小,不稳定可靠

 

我感觉原因可能有两个,一个是客户端发送过快,网络状况不好或者超过服务器接收速度,就会丢包。

第二个原因是服务器收到包后,还要进行一些处理,而这段时间客户端发送的包没有去收,造成丢包。

 

解决方法:

方法一:客户端降低发送速度,可以等待回包,或者加一些延迟。

方法二:服务器部分单独开一个线程,去接收UDP数据,存放在一个缓冲区中,又另外的线程去处理收到的数据,尽量减少因为处理数据延时造成的丢包。

 

有两种方法解决楼主的问题:

方法一:重新设计一下协议,增加接收确认超时重发。(推荐)

方法二:在接收方,将通信和处理分开,增加个应用缓冲区;如果有需要增加接收socket的系统缓冲区。(本方法不能从根本解决问题,只能改善)

 

网络丢包,是再正常不过的了。

既然用UDP,就要接受丢包的现实,否则请用TCP。

如果必须使用UDP,而且丢包又是不能接受的,只好自己实现确认和重传,说白了,就是自己实现TCP(当然是部分和有限的简单实现)。

 

UDP是而向无连接的,用户在实施UDP编程时,必须制定上层的协议,包括流控制,简单的超时和重传机制,如果不要求是实时数据,我想TCP可能会更适合你!

5、java读取clob字段的几种方法

第一种
Clob clob = rs.getClob("remark");//java.sql.Clob
String detailinfo = "";
if(clob != null){
    detailinfo = clob.getSubString((long)1,(int)clob.length());
}

第二种:
Clob clob = rs.getClob("remark");//java.sql.Clob
int i = 0;
if(clob != null){
     InputStream input = clob.getAsciiStream();
     int len = (int)clob.length();
     byte by[] = new byte[len];
     while(-1 != (i = input.read(by, 0, by.length))){
      input.read(by, 0, i);
     }
     detailinfo = new String(by, "utf-8");
}

第三种:
Clob clob = rs.getClob("remark");//java.sql.Clob
String value="";
String line="";
if(clob!=null){
    Reader reader=((oracle.sql.CLOB)clob).getCharacterStream();
    BufferedReader br=new BufferedReader(reader);
    while((line=br.readLine())!=null){
         value += line + "\r\n";
    }

} 

第一种方法代码量少,且能避免中文乱码问题;第二种方法与第一种方法效率差不多,也是常使用的一种方法;第三种方法效率极低,如果数据比较大的话建议不要使用。

6、Url请求方式中文乱码问题解决 

jsp中post方式请求一般不会乱码,如果乱码加上这句:
解决办法一
request.setCharacterEncoding("utf-8");
而get方式请求,若url含非西欧编码必然会乱码,处理方式:
request.setCharacterEncoding("utf-8");
//将请求参数使用ISO-8859-1分解成字节数组,再将字节数组解码成字符串
String name = new String(request.getParamet("name").getBytes("ISO-8859-1"),"utf-8");

解决办法二
java.net.URLEncoder.encode()传送字符编码
面贴一下解决这个问题参考的文章:
使用java.net.URLEncoder.encode()可以对要传递的中文进行编码
a.在传参数之前先把参数进行转码:java.net.URLEncoder.encode(param);
取值时用语句java.net.URLDecoder.decode(param);再转回中文
b.在你的Tomcat目录-->conf目录-->server.xml里找出这段:
  <Connector
          port="8080"  maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
                enableLookups="false" redirectPort="8443(www.111cn.net)" acceptCount="100"
                debug="0" connectionTimeout="20000"
                disableUploadTimeout="true"
 <!--在里边加上这个参数-->
URIEncoding="gb2312" />

 

分享到:
评论

相关推荐

    java中操作oracle的CLOB字段精解

    Java 中操作 Oracle 的 CLOB 字段精解 Java 中操作 Oracle 的 CLOB 字段是一种常见的操作,在实际开发中,我们经常需要在 Oracle 数据库中存储和读取大型文本数据,这时就需要使用 CLOB(Character Large OBject)...

    dblink_clob字段异常解决方案

    在数据库.link连接远程数据库时,经常会遇到无法使用CLOB字段的问题,这是因为CLOB字段在远程数据库中的处理方式与本地数据库不同所导致的。下面将讨论解决dblink_clob字段异常的解决方案。 什么是dblink? DBLink...

    运用Java如何存取Oracle中的CLOB类型字段

    在Java中处理Oracle的CLOB字段,首先需要导入相关的Java SQL包以及Oracle JDBC驱动特有的类。这些包括`java.sql.*`,`java.io.*`,以及`oracle.jdbc.driver.*`和`oracle.sql.*`。这一步是建立与Oracle数据库连接的...

    java读写oracle clob字段

    本教程将介绍如何使用Java来读取和写入Oracle数据库中的CLOB字段。 首先,我们需要引入相关的Java和Oracle JDBC驱动库。在上述代码中,我们看到`import oracle.jdbc.driver.OracleDriver;`,这表示我们将使用Oracle...

    jdbc 处理clob类型字段

    在Java编程中,JDBC(Java Database Connectivity)是用于与各种数据库进行交互的一套标准API。当我们在处理大型文本数据时,例如XML文档、长篇文章或者大段代码,数据库通常会提供CLOB(Character Large Object)...

    数据库读取clob字段

    ### 数据库读取CLOB字段 #### 概述 在Oracle数据库中,CLOB(Character Large Object)是一种用于存储大量文本数据的数据类型。CLOB能够容纳4GB的文本信息,适用于存储如文章、报告或者XML文档等大型文本数据。...

    读取oracle数据库中clob字段的值

    ### 读取Oracle数据库中CLOB字段的值 在处理Oracle数据库时,经常会遇到需要读取CLOB(Character Large Object)类型字段的情况。CLOB主要用于存储大量的文本数据,如文章、文档等内容。由于CLOB类型的数据量可能...

    修改clob blob 字段

    修改clob blob 字段 修改clob blob 字段 修改clob blob 字段

    CLOB 字段类型报错 ORA-01704: 文字字符串过长的解决

    在Oracle数据库中,CLOB(Character Large Object)字段类型用于存储大量的文本数据,如XML文档、长篇文章或者大量字符数据。然而,当你尝试向CLOB字段插入数据时,如果超过了Oracle规定的最大限制,就会遇到“ORA-...

    jdbc读写Oracle的CLOB字段

    JDBC读写Oracle的CLOB字段

    ORACLE中CLOB字段转String类型

    ### ORACLE中CLOB字段转String类型 在Oracle数据库中,`CLOB`(Character Large Object)是一种用于存储大量文本数据的数据类型。由于其能够存储非常大的文本块(最大可达4GB),因此常被用于存储文章、报告或任何...

    java读取oracle数据库中clob字段.txt

    java读取oracle数据库中clob字段 把oracle数据库中字段类型为clob的字段值以字符串的形式读取出来

    Oracle如何对CLOB行字段来执行全文检索

    Oracle CLOB 行字段全文检索实现方法 Oracle 数据库中,CLOB 行字段是一种常用的数据类型,用于存储大文本数据。然而,在 Oracle8i 版本之前,对大字段 CLOB 仍然不支持在 where 子句直接的 Like 操作。这使得...

    JAVA对clob的操作

    CLOB操作与BLOB操作类似,但是在获取java.sql.Clob对象后需要强制转换为oracle.sql.CLOB对象,以便使用getCharacterOutputStream()方法将数据写入CLOB字段。 三、出库操作 出库操作可以使用ResultSet.getBlob()或...

    Oracle导出Clob,Blob工具

    在描述中提到的“Oracle导出Clob,Blob等大字段工具”就是为了解决这个问题而设计的,它是一个自编写的实用程序,方便用户导出和管理Oracle数据库中的大对象数据。 Oracle数据库中的Clob类型用于存储大量的文本数据...

    Mybatis 处理 CLOB、BLOB 类型数据

    Mybatis 处理 CLOB、BLOB 类型数据 MyBatis 处理 CLOB、BLOB 类型数据是指在使用 MyBatis 框架时,如何正确地处理大字段类型的数据。CLOB(Character Large OBject)和 BLOB(Binary Large OBject)都是大字段类型...

    Hibernate存储Clob字段的方式总结

    Hibernate存储Clob字段的方式总结涉及了在Java开发中使用Hibernate操作大型文本字段Clob的操作方法。本文主要介绍了两种操作Clob字段的方法,一种是将Clob字段直接映射为String类型,另一种是使用Clob类型进行处理。...

    CLOB字段处理

    在 Java 中,通过使用 oracle.sql.CLOB 类来处理 CLOB 类型字段的存储和读取。 在 Java 中,连接 Oracle 数据库需要使用 Oracle 的 JDBC 驱动程序。首先,需要使用 Class.forName() 方法加载驱动程序,然后使用 ...

Global site tag (gtag.js) - Google Analytics