android与pc的简单交互(udp+tcp的socket方式)
来源:互联网 发布:c字符数组初始化 编辑:程序博客网 时间:2024/05/01 08:15
<span style="font-size: 12px; font-family: Arial, Helvetica, sans-serif;">近段时间,公司提出数据本地化的要求,即把数据放到用户的电脑客户端内,而android客户端则通过wifi局域网和用户所使用的电脑里的 客户端程序进行交互..那么这样一来第一个难题 摆在我的面前.就是我如何与用户的电脑里的客户端和我android建立连接 .两个应用程序之间要相互连接必然要知道彼此的ip和统一的端口号才能进行连接那么如何获得ip呢? </span>
android端
// 获取本机WIFIpublic String getLocalIpAddress(Context context) {WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);WifiInfo wifiInfo = wifiManager.getConnectionInfo();// 获取32位整型IP地址int ipAddress = wifiInfo.getIpAddress();// 返回整型地址转换成“*.*.*.*”地址return String.format("%d.%d.%d.%d", (ipAddress & 0xff),(ipAddress >> 8 & 0xff), (ipAddress >> 16 & 0xff),(ipAddress >> 24 & 0xff));}而我用Java模拟pc客户端在获取地址的时候遇到一点小问题,因为我想获得的是 pc在局域网下的ip地址 而不是广域网下面的ip地址
String string = null;try {string = InetAddress.getLocalHost().getHostAddress();//返回的是广域网下本机的ip地址 } catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(string);通过各种资料以及朋友提供帮助找到以下代码,从而获得了本机在局域网下ip地址
/** * 获取本地 ip * @return */public String getLocalIPAddress() {try {for (Enumeration<NetworkInterface> mEnumeration = NetworkInterface.getNetworkInterfaces(); mEnumeration.hasMoreElements();) {NetworkInterface intf = mEnumeration.nextElement();for (Enumeration<InetAddress> enumIPAddr = intf.getInetAddresses(); enumIPAddr.hasMoreElements();) {InetAddress inetAddress = enumIPAddr.nextElement();// 如果不是回环地址if (!inetAddress.isLoopbackAddress()) {// 直接返回本地IP地址return inetAddress.getHostAddress().toString();}}}} catch (SocketException ex) {System.err.print("error");}return null;}
服务端核心代码
1.接收来自客户端的udp信息,从而得到目标客户端的ip地址,2,开启线程向其客户端发送udp信息,避免重复线程,需要判断,.3.一个基于tcp方式的socket连接用于最后移除对应的线程执行节约资源.
public void ServerReceviedByUdp() {// 创建一个DatagramSocket对象,并指定监听端口。(UDP使用DatagramSocket)DatagramSocket socket = null;try {// 创建一个byte类型的数组,用于存放接收到得数据socket = new DatagramSocket(10025);while (true) {byte data[] = new byte[4 * 1024];// 创建一个DatagramPacket对象,并指定DatagramPacket对象的大小final DatagramPacket packet = new DatagramPacket(data, data.length);// 读取接收到得数据//System.out.println("server--begin");socket.receive(packet);// 把客户端发送的数据转换为字符串。// 使用三个参数的String方法。参数一:数据包 参数二:起始位置 参数三:数据包长synchronized (packet) {String result = new String(packet.getData(),packet.getOffset(), packet.getLength());//System.out.println("sever--"+result); SendUDPPacket sendUDPPacket=SendUDPPacket.newInstance(packet);//由于android客户端只能接收包含本机ip的udp包所以这里用一个伪单例类用于发送udp包给客户端 if (!SendUDPPacket.getThreadList(packet)) {//判断是否存在与发送队列里,避免重复向同一个客户端开启不必要的线程 sendUDPPacket.sendMessage();//开启线程 发送信息} }}} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (socket != null)socket.close();}}
package com.cfanle.server;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.Inet4Address;import java.net.InetAddress;import java.net.NetworkInterface;import java.net.SocketException;import java.net.UnknownHostException;import java.util.ArrayList;import java.util.Collections;import java.util.Enumeration;import java.util.Iterator;import java.util.List;import com.google.gson.Gson;import com.google.gson.JsonObject;/** * 服务端入口类 * @author yx * */public class Server { // 获取本地IP函数/** * 获取本地 ip * @return */public String getLocalIPAddress() {try {for (Enumeration<NetworkInterface> mEnumeration = NetworkInterface.getNetworkInterfaces(); mEnumeration.hasMoreElements();) {NetworkInterface intf = mEnumeration.nextElement();for (Enumeration<InetAddress> enumIPAddr = intf.getInetAddresses(); enumIPAddr.hasMoreElements();) {InetAddress inetAddress = enumIPAddr.nextElement();// 如果不是回环地址if (!inetAddress.isLoopbackAddress()) {// 直接返回本地IP地址return inetAddress.getHostAddress().toString();}}}} catch (SocketException ex) {System.err.print("error");}return null;}public static void main(String[] args) {System.out.println(new Server().getLocalIPAddress());// test();Server server = new Server();String string = null;try {string = InetAddress.getLocalHost().getHostAddress();} catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(string);server.ServerReceviedByUdp();// new ClientSever(null).start();} private ArrayList<String> ips;public void ServerReceviedByUdp() {// 创建一个DatagramSocket对象,并指定监听端口。(UDP使用DatagramSocket)DatagramSocket socket = null;try {// 创建一个byte类型的数组,用于存放接收到得数据socket = new DatagramSocket(10025);while (true) {byte data[] = new byte[4 * 1024];// 创建一个DatagramPacket对象,并指定DatagramPacket对象的大小final DatagramPacket packet = new DatagramPacket(data, data.length);// 读取接收到得数据//System.out.println("server--begin");socket.receive(packet);// 把客户端发送的数据转换为字符串。// 使用三个参数的String方法。参数一:数据包 参数二:起始位置 参数三:数据包长synchronized (packet) {String result = new String(packet.getData(),packet.getOffset(), packet.getLength());//System.out.println("sever--"+result); SendUDPPacket sendUDPPacket=SendUDPPacket.newInstance(packet); if (!SendUDPPacket.getThreadList(packet)) { sendUDPPacket.sendMessage();}}}} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (socket != null)socket.close();}} }
package com.cfanle.server;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import java.net.SocketException;import java.net.UnknownHostException;import java.util.ArrayList;import java.util.List;import java.util.Scanner;import com.google.gson.Gson;import com.google.gson.JsonObject;/** * 给客户端发送信息的具体实现类 * @author yx * */public class SendUDPPacket extends Thread implements KillUDPSendMessage {// private static SendUDPPacket packet;private DatagramPacket packet;private static MyTcpSocket myTcpSocket;private static List<SendUDPPacket> threadList;private SendUDPPacket(DatagramPacket packet1) {this.packet = packet1;if (threadList == null)threadList = new ArrayList<>();}public static SendUDPPacket newInstance(DatagramPacket packet1) {int i = 0;SendUDPPacket packet = new SendUDPPacket(packet1);for (i = 0; i < threadList.size(); i++) {SendUDPPacket sendUDPPacket = threadList.get(i);//System.out.println("SendUDPPacket"+sendUDPPacket.getPacket().getAddress().getHostAddress());if (packet1.getAddress().getHostAddress().equals(sendUDPPacket.getPacket().getAddress().getHostAddress())) {break;}}if (i >= threadList.size()) {threadList.add(packet);}return packet;}/** * 开启 发送信息的线程,遍历当前已经连接上的客户端列表 ,为每个客户端开启发送信息的线程 */public void sendMessage() {// do {if (threadList == null) {return;}if (threadList.size() == 0) {return;}for (int i = 0; i < threadList.size(); i++) {Thread thread = threadList.get(i);if (!thread.isAlive()) {thread.start(); System.out.println("thread start");}// threadList.remove(i);}// } while (threadList.size() > 0);}static int count;@Overridepublic void run() {super.run();do {if (threadList == null) {break;}if (threadList.size() == 0) {break;}System.out.println((count++)+"SIZE-==="+threadList.size());send(packet);} while (threadList.size() > 0);if (myTcpSocket!=null) {//停止 tcp方式的 serverSocket线程myTcpSocket.setFlag(false);}}/** * 具体发送udp信息的方法 * @param packet */private synchronized void send(DatagramPacket packet) {if (packet == null) {return; }String result = new String(packet.getData(), packet.getOffset(),packet.getData().length);JsonObject object = new JsonObject();try {String string = InetAddress.getLocalHost() + "";object.addProperty("addr", new Server().getLocalIPAddress());} catch (UnknownHostException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} try {DatagramSocket socket = new DatagramSocket();// 使用InetAddress(Inet4Address).getByName把IP地址转换为网络地址InetAddress serverAddress = packet.getAddress(); byte data[] = object.toString().getBytes();// 把字符串str字符串转换为字节数组// 创建一个DatagramPacket对象,用于发送数据。// 参数一:要发送的数据 参数二:数据的长度 参数三:服务端的网络地址 参数四:服务器端端口号DatagramPacket packet1 = new DatagramPacket(data, data.length,InetAddress.getByName(packet.getAddress().getHostAddress()), 65520);socket.send(packet1);socket.close();//System.out.println("服务端 65520已经发送信息");if (myTcpSocket==null) {myTcpSocket=new MyTcpSocket(this);myTcpSocket.start();}else if (!myTcpSocket.isAlive()) {myTcpSocket.setFlag(true);myTcpSocket.start();}} catch (SocketException e) {e.printStackTrace();} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}public static boolean getThreadList(DatagramPacket packet) {if (threadList==null) {return true;}int i,count=threadList.size();String newIp=packet.getAddress().getHostAddress();for (i = 0; i < count; i++) {SendUDPPacket packet2=threadList.get(i);String ip=packet2.getPacket().getAddress().getHostAddress();if (newIp.equals(ip)) {break;}}return i==count;}public DatagramPacket getPacket() {return packet;}/** * tcp线程 连接类 * @author yx * */class MyTcpSocket extends Thread { private KillUDPSendMessage message;private boolean flag;public MyTcpSocket(KillUDPSendMessage message) {flag=true;this.message=message;}@Overridepublic void run() {ServerSocket serverSocket=null; do {try {if (serverSocket==null) { serverSocket=new ServerSocket(50520);}startSeverSocket(serverSocket);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{if (serverSocket!=null) {try {serverSocket.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}} while (flag);}private void startSeverSocket(ServerSocket serverSocket) throws Exception { Socket socket=serverSocket.accept();String ip= serverSocket.getInetAddress().getHostAddress();Scanner scanner=new Scanner(socket.getInputStream());StringBuffer buffer=new StringBuffer();while (scanner.hasNextLine()) {buffer.append(scanner.nextLine());}Mode mode1=new Gson().fromJson(buffer.toString(), Mode.class);System.out.println(buffer+"FROM "+mode1.getAddr());socket.close();if (message!=null) {message.killUDPMessageAtIP(mode1.getAddr());}}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}}@Overridepublic void killUDPMessageAtIP(String ip) {for (int i = 0; i < threadList.size(); i++) {String nipString=threadList.get(i).getPacket().getAddress().getHostAddress();if (nipString.equals(ip)) {threadList.remove(i);break;}}}}
package com.cfanle.server;public interface KillUDPSendMessage {void killUDPMessageAtIP(String ip);}
android端代码整理后如下
package com.cfanle.mode;public class SocketResult {private String addr;public SocketResult() {}public String getAddr() {return addr;}public void setAddr(String addr) {this.addr = addr;}}
package com.cfanle.tcputils;/** * 接收android以服务端身份监听socket所得到的信息回调接口 * @author yx * */public interface ReciveSockectInfo {/** * 获得socket中的信息 * @param res */void getResult(String res);}
package com.cfanle.tcputils;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.io.Reader;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import java.net.UnknownHostException;import java.util.Scanner;import com.cfanle.mode.SocketResult;import com.cfanle.utils.UIUtils;import com.cfanle.utils.WifiUtls;import com.google.gson.JsonObject; public class TCPSockectSever {private static TCPSockectSever sever;public TCPSockectSever() {// TODO Auto-generated constructor stubn } public static TCPSockectSever newInstance() {if (sever==null) {sever=new TCPSockectSever();}return sever;}public void waitSocketConnection(int port,ReciveSockectInfo info) throws Exception {// 为了简单起见,所有的异常信息都往外抛//int port = 8899;// 定义一个ServerSocket监听在端口8899上ServerSocket server = new ServerSocket(port);// server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的//while (true) {Socket socket = server.accept();// 跟客户端建立好连接之后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。Reader reader = new InputStreamReader(socket.getInputStream());char chars[] = new char[64];int len;StringBuilder sb = new StringBuilder();while ((len = reader.read(chars)) != -1) {sb.append(new String(chars, 0, len));}System.out.println("from client: " + sb);if (info!=null) {info.getResult(sb.toString());}reader.close();socket.close();server.close();}public void connPCServer(String ip,String data,int port) throws UnknownHostException, Exception {Socket socket=new Socket(InetAddress.getByName(ip), port);PrintStream printStream=new PrintStream(socket.getOutputStream());printStream.print(data);socket.getOutputStream().close();printStream.close();//Scanner scanner=new Scanner(socket.getInputStream());//StringBuffer buffer=new StringBuffer();//while (scanner.hasNextLine()) {//buffer.append(scanner.nextLine());//}//socket.getInputStream().close();//scanner.close();//UIUtils.newInstance().nsLog(buffer.toString(), getClass());socket.close();}}
package com.cfanle.udputils;public interface IResult {void result(String res);}
package com.cfanle.udputils;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.SocketException;import java.net.UnknownHostException;import org.json.JSONException;import org.json.JSONObject;import com.cfanle.utils.UIUtils;import android.content.Context;import android.net.wifi.WifiManager; public class UDPUtils {private static UDPUtils udpUtils;private UDPUtils() {}public static UDPUtils newInstance() {if (udpUtils==null) {udpUtils=new UDPUtils();}return udpUtils;}public void sendToServerWithUDPSocket(String datas, int port) {DatagramSocket socket;try {// 创建DatagramSocket对象并指定一个端口号,注意,如果客户端需要接收服务器的返回数据,// 还需要使用这个端口号来receive,所以一定要记住socket = new DatagramSocket();// 使用InetAddress(Inet4Address).getByName把IP地址转换为网络地址// InetAddress serverAddress = InetAddress.getLocalHost();InetAddress serverAddress = InetAddress.getByName("255.255.255.255");// JSONObject object=new JSONObject();// object.put("addr", new WifiUtls().getLocalIpAddress(this));String str = "[2143213;21343fjks;213]";// 设置要发送的报文byte data[] = datas.toString().getBytes();// 把字符串str字符串转换为字节数组// 创建一个DatagramPacket对象,用于发送数据。// 参数一:要发送的数据 参数二:数据的长度 参数三:服务端的网络地址 参数四:服务器端端口号DatagramPacket packet = new DatagramPacket(data, data.length,serverAddress, port);// 10025socket.send(packet);// 把数据发送到服务端。// ServerReceviedByUdp();} catch (SocketException e) {e.printStackTrace();} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}public void ServerReceviedByUdp(Context context,int port,IResult backResult) {// 创建一个DatagramSocket对象,并指定监听端口。(UDP使用DatagramSocket)DatagramSocket socket = null; try {socket = new DatagramSocket(port);//65520// 创建一个byte类型的数组,用于存放接收到得数据socket.setBroadcast(true);//while (true) {byte data[] = new byte[4 * 1024];// 创建一个DatagramPacket对象,并指定DatagramPacket对象的大小DatagramPacket packet = new DatagramPacket(data, data.length);// 读取接收到得数据//System.out.println("begin");UIUtils.newInstance().nsLog("reciveDatagramPacket begin",getClass());WifiManager manager=(WifiManager) context.getSystemService(Context.WIFI_SERVICE);WifiManager.MulticastLock lock=manager.createMulticastLock("t00udp");lock.acquire();socket.receive(packet);// 把客户端发送的数据转换为字符串。// 使用三个参数的String方法。参数一:数据包 参数二:起始位置 参数三:数据包长synchronized (packet) {String result = new String(packet.getData(),packet.getOffset(), packet.getLength());System.out.println("redsfh-------"+result+"==========="+(backResult!=null));if (backResult!=null) {UIUtils.newInstance().nsLog("{back activity", getClass());backResult.result(result);}//JSONObject object=new JSONObject(result);}lock.release();//}} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{if (socket!=null) {socket.close();}}}}
package com.cfanle.utilsmanager;import java.net.UnknownHostException;import android.R.integer;import android.content.Context;import com.cfanle.tcputils.ReciveSockectInfo;import com.cfanle.tcputils.TCPSockectSever;import com.cfanle.udputils.IResult;import com.cfanle.udputils.UDPUtils;public class MySocketManager {private static MySocketManager manager;private MySocketManager() {}public static MySocketManager newInstance() {if (manager==null) { manager=new MySocketManager();} return manager;}//***************udp**********************V //发送udp包public void sendUDPPacket(String datas, int port) {UDPUtils.newInstance().sendToServerWithUDPSocket(""+datas, port);}//接收udp包public void reciveUDPPackket(Context context,int porrt,IResult backResult) {if (context==null) {throw new RuntimeException("context must be not null");}UDPUtils.newInstance().ServerReceviedByUdp(context,porrt, backResult);}//****************TCP***********************************/** * 启动android端 服务器端模式监听socket端口 * @param port 端口号 * @param info 返回的内容 * @throws Exception */public void startSeverSocket(int port,ReciveSockectInfo info) throws Exception {TCPSockectSever.newInstance().waitSocketConnection(port, info);}public void callServerIsSuccus(String ip,String str, int port) throws UnknownHostException, Exception {TCPSockectSever.newInstance().connPCServer(ip, str,port);}}
package com.example.myudpandtcpsocket; import java.net.UnknownHostException;import com.cfanle.mode.SocketResult;import com.cfanle.tcputils.ReciveSockectInfo;import com.cfanle.udputils.IResult;import com.cfanle.utils.UIUtils;import com.cfanle.utils.WifiUtls;import com.cfanle.utilsmanager.MySocketManager;import com.google.gson.Gson;import com.google.gson.JsonObject;import android.app.IntentService;import android.content.Intent;import android.text.TextUtils;public class MyUDPSendService extends IntentService implements ReciveSockectInfo, IResult {private static boolean isSendUDP=true;private static ReciveSockectInfo info;public MyUDPSendService() {super("MYUDP");// TODO Auto-generated constructor stub}public static void setReciveInfoListenner(ReciveSockectInfo info1) {info=info1;}@Overrideprotected void onHandleIntent(Intent intent) {UIUtils.newInstance().nsLog("service onHandleIntent", getClass());new Thread(new Runnable() {@Overridepublic void run() {try {//MySocketManager.newInstance().startSeverSocket(8899, MyUDPSendService.this);//do {//UIUtils.newInstance().nsLog("sendUDPPacketbegin----", getClass());MySocketManager.newInstance().sendUDPPacket("from android ", 10025);//} while (isSendUDP);} catch (Exception e) {new Thread(this).start();e.printStackTrace();}}}).start();while (isSendUDP) {UIUtils.newInstance().nsLog("reciveUDPPackket begin----", getClass());MySocketManager.newInstance().reciveUDPPackket( MyUDPSendService.this, 65520, this);}//MySocketManager.newInstance().callServerIsSuccus(ip, port);}@Overridepublic void getResult(String res) {SocketResult result=new Gson().fromJson(res, SocketResult.class);if (!TextUtils.isEmpty(result.getAddr())) {isSendUDP=false;try {SocketResult resultSocket=new SocketResult();resultSocket.setAddr(new WifiUtls().getLocalIpAddress(this));String str=new Gson().toJson(resultSocket);MySocketManager.newInstance().callServerIsSuccus(result.getAddr(), str,50520);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}if (info!=null) {info.getResult(result.getAddr());}}}@Overridepublic void result(String res) {SocketResult result=new Gson().fromJson(res, SocketResult.class);UIUtils.newInstance().nsLog(res+"==="+result, getClass());if (!TextUtils.isEmpty(result.getAddr())) {isSendUDP=false;try {SocketResult resultSocket=new SocketResult();resultSocket.setAddr(new WifiUtls().getLocalIpAddress(this));String str=new Gson().toJson(resultSocket);MySocketManager.newInstance().callServerIsSuccus(result.getAddr(), str,50520);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}if (info!=null) {info.getResult(result.getAddr());}}}}
package com.example.myudpandtcpsocket;import java.util.Scanner;import com.cfanle.tcputils.ReciveSockectInfo;import com.lidroid.xutils.HttpUtils;import com.lidroid.xutils.exception.HttpException;import com.lidroid.xutils.http.ResponseStream;import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.widget.TextView;public class MainActivity extends Activity implements ReciveSockectInfo {private TextView textView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = (TextView) findViewById(R.id.textView1);}public void click(View view) {startService(new Intent(this, MyUDPSendService.class));MyUDPSendService.setReciveInfoListenner(this);}@Overridepublic void getResult(final String res) {this.runOnUiThread(new Runnable() {@Overridepublic void run() {textView.setText("sever ip is --" + res);MainActivity.this.stopService(new Intent(MainActivity.this,MyUDPSendService.class));}});}}
1 0
- android与pc的简单交互(udp+tcp的socket方式)
- PC与Android模拟器UDP/TCP 通信的端口问题
- PC与Android模拟器UDP/TCP 通信的端口问题
- TCP与UDP的简单发送与实现(socket)
- socket通讯tcp与udp的区别
- socket tcp与udp的区别
- linux简单的TCP与UDP的socket程序以及机器大小端的判断程序
- linux简单的TCP与UDP的socket程序以及机器大小端的判断程序
- TCP与UDP的简单图解
- linux socket编程以及简单的tcp,udp的例子
- 基于socket的TCP和UDP通讯的简单建立
- Android与PC的Socket(TCP/IP)通信(by USB) 拒绝连接的
- Android Socket UDP通信的简单演示
- python socket实现简单的(TCP/UDP)服务器/客户端
- Android与PC的Socket(TCP/IP)通信(by USB)
- Android与PC的socket通信
- android与pc的socket通信JAVA
- [TCP/IP] TCP与UDP不同的包处理方式
- 核心期刊
- Xcode The Simulator can't be launched because it is already in use .
- Android:EditText 多行显示及所有属性
- JAVA帮助文档全系列 JDK1.5 JDK1.6 JDK1.7 官方中英完整版下载
- Linux系统ELF文件二进制格式分析(二)
- android与pc的简单交互(udp+tcp的socket方式)
- IDEA如何安装mybatis插件
- Debug With GDB: Segmentation Fault Example
- CERC 2012 B Who wants to live forever 分治
- AngularJs 中的ng-if ng-swith ng-bind-template
- Android 系统状态栏一体化
- js数组的排序——sort()
- php5.4.0以后加入trait实现代码复用【摘录】
- oracle join(比较全面的解释了join)