`

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字段

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

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

    JAVA对clob的操作

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

    ORACLE中CLOB字段转String类型

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

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

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

    Mybatis 处理 CLOB、BLOB 类型数据

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

    Oracle导出Clob,Blob工具

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

    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