通讯,源于网络,网络从下到上,分为7层:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层;通讯,基于协议,常用的协议有很多,比如网络层协议IP、传输层协议TCP/UDP、应用层协议HTTP/SOAP/REST等。
我们还会经常听到Socket,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。有个形象的比喻:HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
任何语言,都会提供对通讯的支持,我们今天用Java语言,演示几种在Java中比较常用的通讯技术,包括:Socket、Http、REST、Dubbo、Thrift、FTP。
SocketServer.java
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SocketServer { public static void main(String[] args) { SocketServer ss = new SocketServer(); //设定服务端的端口号 ServerSocket s = null; try { s = new ServerSocket(10099); System.out.println("ServerSocket Start:"+s); while(true) { Socket socket = s.accept(); //这个地方是阻塞的 System.out.println("Server_Accept:"+socket); SocketServer.HandleSocket vsm = ss.new HandleSocket(socket); new Thread(vsm).start(); } } catch (IOException e) { e.printStackTrace(); } finally { try { s.close(); } catch (IOException e) { } } } class HandleSocket implements Runnable { private Socket socket; public HandleSocket(Socket socket) { this.socket = socket; } @Override public void run() { BufferedReader br = null; PrintWriter pw = null; try { //用于接收客户端发来的请求 br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //用于发送返回信息,可以不需要装饰这么多io流使用缓冲流时发送数据要注意调用.flush()方法 pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true); String str = br.readLine(); if(str != null) { pw.println("OK_"+Thread.currentThread().getName()); pw.flush(); System.out.println("Command:"+str); } } catch (Exception e) { e.printStackTrace(); }finally{ System.out.println("Server_Close:"+socket); try { br.close(); pw.close(); socket.close(); } catch (Exception e2) { } } } } }
SocketClient.java
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; public class SocketClient { public static void main(String[] args) throws InterruptedException { for(int i=0;i<10;i++) { call( "Hello" + i); } } public static void call(String command) { Socket socket = null; BufferedReader br = null; PrintWriter pw = null; try { //客户端socket指定服务器的地址和端口号 socket = new Socket("127.0.0.1", 10099); System.out.println("Client_Open" + socket + " Command:" + command); //同服务器原理一样 br = new BufferedReader(new InputStreamReader(socket.getInputStream())); pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))); pw.println(command); pw.flush(); String str = br.readLine(); System.out.println("Client_Receive:"+str); } catch (Exception e) { e.printStackTrace(); } finally { try { System.out.println("Client_Close:"+socket); br.close(); pw.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } } }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; public class HttpConnectionTest { public static void main(String[] args) throws Exception { System.out.println("begin send"); String inputParam = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><content>Test</content></page>"; URL url = null; HttpURLConnection httpConn = null; OutputStream output = null; OutputStreamWriter outr = null; //url = new URL("http://127.0.0.1:8888/iotest/ReadServlet"); url = new URL("http://www.baidu.com"); httpConn = (HttpURLConnection) url.openConnection(); httpConn.setConnectTimeout(30000); httpConn.setReadTimeout(30000); HttpURLConnection.setFollowRedirects(true); httpConn.setDoOutput(true); httpConn.setRequestMethod("POST"); httpConn.setRequestProperty("Content-Type", "text/xml"); httpConn.connect(); output = httpConn.getOutputStream(); outr = new OutputStreamWriter(output); // 写入请求参数 outr.write(inputParam.toString().toCharArray(), 0, inputParam.toString().length()); outr.flush(); outr.close(); System.out.println("send ok"); int code = httpConn.getResponseCode(); System.out.println("code " + code); System.out.println(httpConn.getResponseMessage()); //读取响应内容 String sCurrentLine = ""; String sTotalString = ""; if (code == 200) { java.io.InputStream is = httpConn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); while ((sCurrentLine = reader.readLine()) != null) if (sCurrentLine.length() > 0) sTotalString = sTotalString + sCurrentLine.trim(); } else { sTotalString = "远程服务器连接失败,错误代码:" + code; } System.out.println("response:" + sTotalString); } }
官网:http://hc.apache.org/
已经废弃的Jar(这个项目,自从2007年8月份就不再维护了,已经迁移到org.apache.httpcomponents了):
<dependency> <groupId>commons-httpclient</groupId> <artifactId>commons-httpclient</artifactId> <version>3.1</version> </dependency>
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.2.3</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.2.3</version> </dependency>
import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.KeyStore; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.HttpException; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.HttpParams; import com.creditease.ns.oltp.tunneladapter.tunnels.cb.util.CbConst; /** * 更多参考网址:http://hc.apache.org/ * */ public class HttpClientTest { static String url = "http://www.tuicool.com/"; public static void main(String[] args) throws HttpException, IOException { testHttp2(); } public static void testHttp2() { org.apache.http.client.HttpClient httpClient = null; HttpPost httpPost = null; InputStream in = null; httpClient = new DefaultHttpClient(); httpPost = new HttpPost(url); String resp = ""; try { httpClient = new DefaultHttpClient(); httpPost = new HttpPost(url); if (url.indexOf("https") != -1) { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); in = new FileInputStream("quick.keystore"); keyStore.load(in, "chinabank".toCharArray()); SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore); Scheme scheme = new Scheme("https", 443, sslSocketFactory); httpClient.getConnectionManager().getSchemeRegistry().register(scheme); } HttpParams httpParams = httpClient.getParams(); httpParams.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000 * 20); httpParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 1000 * 40); List<NameValuePair> reqPair = new ArrayList<NameValuePair>(); reqPair.add(new BasicNameValuePair("charset", "UTF-8")); reqPair.add(new BasicNameValuePair("req", "nihao")); UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(reqPair, "UTF-8"); httpPost.setEntity(urlEncodedFormEntity); HttpResponse response = httpClient.execute(httpPost); HttpEntity responseEntity = response.getEntity(); if (responseEntity != null) { InputStream is = responseEntity.getContent(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int ch = 0; while ((ch = is.read(buffer)) != -1) { baos.write(buffer, 0, ch); } byte bytes[] = baos.toByteArray(); resp = new String(bytes, CbConst.ENCODING); } int statusCode = response.getStatusLine().getStatusCode(); System.out.println("statusCode:" + statusCode); System.out.println("resp:" + resp); } catch (Exception e) { e.printStackTrace(); } finally { try { if (in != null) { in.close(); } httpPost.releaseConnection(); httpClient.getConnectionManager().shutdown(); } catch (Exception e) { e.printStackTrace(); } } } }
quick.keystore,是一个密码保护的文件,存放私钥和证书。可以通过JDK自带的keytool工具生成。只要有密码,可以提取出私钥和证书。参考网址:
从Java Keystore文件中提取私钥、证书
keystore提取私钥和证书
java 调用 keytool 生成keystore 和 cer 证书
KeyStore中的别名
import java.io.BufferedReader; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map.Entry; import java.util.Timer; import java.util.TimerTask; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class HttpSocketPressTest { private Long succNum = 0L; private Long failNum = 0L; private Long connFailNum = 0L; private Long readFailNum = 0L; private Long otherFailNum = 0L; private Long beginTime = System.currentTimeMillis(); private Boolean recordSuccReturn = false; private String url = "http://www.baidu.com"; public static final int ThreadNum = 100; public static final int MonitorInterval = 3; public static void main(String[] args) throws Exception { createDir("d:\\httptest\\"); createDir("d:\\httptest\\succ\\"); createDir("d:\\httptest\\fail\\"); createDir("d:\\httptest\\exec\\"); createDir("d:\\httptest\\execother\\"); HttpSocketPressTest hspt = new HttpSocketPressTest(); if ((args != null) && (args.length > 0)) { hspt.setRecordSuccReturn(true); } System.out.println("开" + ThreadNum + "个线程,测试用使用Socket5[10.100.140.85:1080]代理Get方式访问外网。"); System.out.println("如果需要对200返回也记录返回内容,请运行程序时输入任意参数,记录位置d:/httptest/succ。"); System.out.println("异常及非200返回会写在d:/httptest/exception和fail目录。"); ExecutorService executorService = Executors.newFixedThreadPool(ThreadNum); for (int i = 0; i < ThreadNum; i++) { executorService.submit(new HttpConn(hspt)); } Monitor m = new Monitor(hspt); Timer timer = new Timer(); timer.schedule(m, MonitorInterval * 1000, MonitorInterval * 1000); } public synchronized void IncreaseSuccNum() { succNum++; } public synchronized void IncreaseFailNum() { failNum++; } public synchronized void IncreaseConnFailNum() { connFailNum++; } public synchronized void IncreaseReadFailNum() { readFailNum++; } public synchronized void IncreaseOtherFailNum() { otherFailNum++; } public synchronized Long getSuccNum() { return succNum; } public synchronized Long getFailNum() { return failNum; } public synchronized Long getConnFailNum() { return connFailNum; } public synchronized Long getReadFailNum() { return readFailNum; } public synchronized Long getOtherFailNum() { return otherFailNum; } public Long getBeginTime() { return beginTime; } public void setRecordSuccReturn(Boolean b) { recordSuccReturn = b; } public Boolean getRecordSuccReturn() { return recordSuccReturn; } public String getUrl() { return url; } private static void createDir(String dir) { File f = new File(dir); if (!f.exists()) { f.mkdir(); } } } class Monitor extends TimerTask { private HttpSocketPressTest hspt; private Long times = 0L; public Monitor(HttpSocketPressTest hspt) { this.hspt = hspt; } @Override public void run() { Long nowTime = System.currentTimeMillis(); Long interval = nowTime - hspt.getBeginTime(); System.out.println(""); System.out.println("间隔" + HttpSocketPressTest.MonitorInterval + "秒报告一次结果,这是第" + ++times + "次,如下:"); System.out.println("当前时间:" + new Date()); System.out.println("累计运行时间(单位秒):" + (interval / 1000)); System.out.println("成功次数:" + hspt.getSuccNum() + ";平均每秒成功次数:" + ((hspt.getSuccNum() * 1000) / interval)); System.out.println("失败次数:" + hspt.getFailNum() + "【Connection timed out:" + hspt.getConnFailNum() + ",Read timed out:" + hspt.getReadFailNum() + ",其他异常:" + hspt.getOtherFailNum() + "】"); } } class HttpConn implements Runnable { private HttpSocketPressTest hspt; public HttpConn(HttpSocketPressTest hspt) { this.hspt = hspt; } @Override public void run() { while (true) { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss"); String d = sdf.format(new Date()); // System.out.println("[" + d + "] [" + Thread.currentThread().getName() + // "] [访问外网]"); // long startTime = System.currentTimeMillis(); String strUrl = hspt.getUrl(); String domainName = strUrl.split("\\.")[1]; HttpURLConnection httpConn = null; BufferedReader reader = null; try { URL url = null; url = new URL(strUrl); Proxy p; p = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("10.100.140.85", 1080)); httpConn = (HttpURLConnection) url.openConnection(p); httpConn.setConnectTimeout(30 * 1000); httpConn.setReadTimeout(30 * 1000); HttpURLConnection.setFollowRedirects(true); httpConn.setDoOutput(true); httpConn.setRequestMethod("GET"); httpConn.setRequestProperty("Content-Type", "text/xml"); for (Entry<String, List<String>> m : httpConn.getHeaderFields().entrySet()) { // System.out.println(m.getKey() + ":" + m.getValue()); } // 这行代码会报:java.net.ConnectException: Connection timed out: connect httpConn.connect(); int code = httpConn.getResponseCode(); // 读取响应内容 String sCurrentLine = ""; StringBuilder sb = new StringBuilder(); if (code == 200) { hspt.IncreaseSuccNum(); } else { hspt.IncreaseFailNum(); } sb.append("StatusCode:").append(code).append("\n"); sb.append("url:").append(strUrl).append("\n"); InputStream is = httpConn.getInputStream(); reader = new BufferedReader(new InputStreamReader(is)); // 这行代码会报:java.net.SocketTimeoutException: Read timed out while ((sCurrentLine = reader.readLine()) != null) { if (sCurrentLine.length() > 0) { sb.append(sCurrentLine.trim()); } } // System.out.println("接收内容大小:" + sb.toString().length()); if (hspt.getRecordSuccReturn() && (code == 200)) { writeFile("d:\\httptest\\succ\\" + d + "_" + UUID.randomUUID() + ".html", sb.toString()); } if (code != 200) { writeFile("d:\\httptest\\fail\\" + d + "_" + UUID.randomUUID() + ".html", sb.toString()); } } catch (Exception e) { e.printStackTrace(); System.out.println(new Date()); hspt.IncreaseFailNum(); String msg = e.toString(); Boolean isOther = false; if (msg.indexOf("Connection timed out") != -1) { hspt.IncreaseConnFailNum(); } else if (msg.indexOf("Read timed out") != -1) { hspt.IncreaseReadFailNum(); } else { isOther = true; hspt.IncreaseOtherFailNum(); } if (isOther) { writeFile("d:\\httptest\\execother\\" + domainName + "_" + d + "_" + UUID.randomUUID() + ".txt", strUrl + "\r\n" + e); } else { writeFile("d:\\httptest\\exec\\" + domainName + "_" + d + "_" + UUID.randomUUID() + ".txt", strUrl + "\r\n" + e); } } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (httpConn != null) { httpConn.disconnect(); } // System.out.println("[" + d + "] [" + Thread.currentThread().getName() // + "] [访问外网] [cost:[" // + (System.currentTimeMillis() - startTime) + "ms]]"); } } } private void writeFile(String name, String content) { FileWriter writer = null; try { // 打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件 writer = new FileWriter(name, false); writer.write(content); writer.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
...待续
...待续
...待续
...待续