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

2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅

 
 

1 TCP的开销

a  连接协商三次握手,c->syn->s,s->syn ack->c, c->ack->s

b  关闭协商四次握手,c->fin->s, s->ack-c,s->fin->c,c->ack->s

c  保持数据有序,响应确认等计算开销

d  网络拥塞引起的重试开销

2 使用知名端口初始化 serversocket可能需要超级权限。ServerSocket(int port, int backlog)参数backlog用来配置连接队列,在accept之前预先完成连接,加速连接TCP连接阶段,默认为50.

backlog表示ServerSocket可以接受的同时最大连接数量,超过这个连接数量,将会拒绝连接。

如果要提高吞吐量,可以通过设置更大的ServerSocket.setReceiveBufferSize来实现,但是必须在bind之前设置,也就是说要先调用无参构造,然后再调用ServerSocket.bind(SocketAddress endpoint)

3 网络io写操作,提高吞吐量较好的实践有使用java.io.BufferedOutputStream,作为缓冲,减少用户线程和内核线程的切换频率。缓冲区大小一般大于ServerSocket.setReceiveBufferSize。

4 避免对象流死锁,较好的实践是如果要在同一个socket上构建对象输入流和输出流,最好是先构造输出流,再构造输入流。

5 tcp半关闭,shut down output,完成后,对方的read收到eof,结束阻塞。

6 tcp关闭可以用socket.close,socket.getoutputstream.close,socket.getinputstream.close,较好的方式是调用socket.getoutpurtstream.close,它会把未flush的flush掉。三个方法只需调用其中一个即可。isClose方法只会告诉我们本地tcp是否关闭,但是不能告诉我们远程是否关闭。

7 socket read 设置timeout时间,防止无止境阻塞。一般来说,timeout时间会设定为预期时间的两倍。timeout时间设置只对之后的阻塞读有效。

8 每个socket都有send buffer和receive buffer,这个buffer在内核地址空间而非jvm。buffer的size由操作系统实现决定,一般来说是2kb。send buffer可以在tcp关闭前随时设定,通过java.net.Socket.setSendBufferSize(int)设置。但是size的设置只是一种hint,不是绝对值。size设得越大,减少网络写次数,减少拥塞控制,tcp效率、吞吐量越高,类似http://en.wikipedia.org/wiki/Nagle's_algorithm 原理。

一般设定为MSS的三倍;至少大于对方receive buffer;receive buffer也要设定大一点,不拖send buffer后腿;

bufferedoutputstream,bytebuffer一般也要设定为匹配的值;

buffersize(bits)=bandwidth(bits/sec)* delay(sec),有点类似于线程数量的控制,不让cpu闲下来。这边的白话是不让buffer空下来,随时处于最大填充状态。

9 nagle算法,为了提高网络传输效率,减少网络拥塞,延迟小包发送,组装为大包一起发送。默认为开,可以通过setTcpnodelay为true来关闭。一般来说,不会关闭,除非是需要实时交互的场景。另外如果真需要关闭,可以采用巧妙的方式,使用bufferedoutputstream,把buffer size设为大于最大请求或响应包,socket send buffer和receive buffer也设为此值,用一次操作写出请求或响应,bufferedoutputstream.flush,充分利用网络。

10 setlinger,用于关闭socket时,进行磨蹭,拖延。

11 keep alive,是个鸡肋。用于检测连接是否处于连接状态,检测对方是否active。它比较有争议,不是tcp协议的标准内容。另外检测需要消耗网络,当检测对方无反应,socket会被置为reset状态,不可读写。一般不推荐使用。

可以考虑用应用层的心跳检测替代。

参考http://hi.baidu.com/tantea/blog/item/580b9d0218f981793812bb7b.html

12  settrafficclass,设置流量类别,只是hint作用,具体效果取决于实现。有这些类别  IPTOS_LOWCOST (0x02),IPTOS_RELIABILITY (0x04),IPTOS_THROUGHPUT (0x08),IPTOS_LOWDELAY (0x10)

13 接口中文翻译http://hi.baidu.com/%EC%C5%BF%E1%D0%A1%B7%E5/blog/item/5d8e0f58aee147471038c29d.html

 
14 java nio进入新时代,提供非阻塞和多路复用特性,就绪选择器,事件驱动,不再是一个线程处理一个请求,大大节约了线程数量和内存,提高了可伸缩性。
 
15 开发广域网网络应用程序需要考虑防火墙,防火墙分为传输防火墙和应用防火墙,传输防火墙一般会拦截对非知名端口的访问,开放知名端口,如80端口;而应用防火墙一般是代理,在服务端和客户端中间,如http代理http://baike.baidu.com/view/1159398.htm
http隧道穿透防火墙,白话为露丝想写情书给他男朋友,但是他爸妈(防火墙)不允许,于是露丝就把情书包装起来写给她的闺蜜莉莉(http 代理服务器,这个代理服务器在防火墙之内),再由莉莉转交给他男朋友。
 
16 另外是NAT,network address translation。子网共用一个公共ip,对外界透明。http://baike.baidu.com/view/16102.htm
 
17 UDP size比较受限(512kb),不可靠,无连接,但是成本低。丢失不重发,重发需要应用控制,要考虑发送消息是否幂等。UDP数据报是个独立传输单位,在java里UDP用java.net.DatagramPacket。适用于发送心跳场景。DatagramSocket的connect,close操作都是针对本地的,并无对连接产生什么效果,毕竟是无连接协议。
如果想提高可靠度,可以在应用实现,clinet维护一个序列号,等待server响应这个序列号,否则进行重发策略。/*
Java代码 
  1. * ReliableDatagramSocket.java.
  2. * Copyright ? Esmond Pitt, 1997, 2005. All rights reserved.
  3. * Permission to use is granted provided this copyright
  4. * and permission notice is preserved.
  5. */
  6. import java.io.*;
  7. import java.net.*;
  8. import java.text.*;
  9. import java.util.*;
  10. // All times are expressed in seconds.
  11. // ReliabilityConstants interface, just defines constants.
  12. interface ReliabilityConstants
  13. {
  14. // Timeout minima/maxima
  15. public static final int MIN_RETRANSMIT_TIMEOUT = 1;
  16. public static final int MAX_RETRANSMIT_TIMEOUT = 64;
  17. // Maximum retransmissions per datagram, suggest 3 or 4.
  18. public static final int MAX_RETRANSMISSIONS = 4;
  19. }
  20. The  D;; class manages current and smoothed round-trip timers
  21. and the related timeouts:
  22. // RoundTripTimer class.
  23. class RoundTripTimer implements ReliabilityConstants
  24. {
  25. float roundTripTime = 0.0f;// most recent RTT
  26. float smoothedTripTime = 0.0f;// smoothed RTT
  27. float deviation = 0.75f; // smoothed mean deviation
  28. short retransmissions = 0;// retransmit count: 0, 1, 2, …
  29. // current retransmit timeout
  30. float currentTimeout =
  31. minmax(calculateRetransmitTimeout());
  32. /** @return the re-transmission timeout. */
  33. private int calculateRetransmitTimeout()
  34. {
  35. return (int)(smoothedTripTime+4.0*deviation);
  36. }
  37. /** @return the bounded retransmission timeout. */
  38. private float minmax(float rto)
  39. {
  40. return Math.min
  41. (Math.max(rto, MIN_RETRANSMIT_TIMEOUT),
  42. MAX_RETRANSMIT_TIMEOUT);
  43. }
  44. /** Called before each new packet is transmitted. */
  45. void newPacket()
  46. {
  47. retransmissions = 0;
  48. }
  49. /**
  50. * @return the timeout for the packet.
  51. */
  52. float currentTimeout()
  53. {
  54. return currentTimeout;
  55. }
  56. /**
  57. * Called straight after a successful receive.
  58. * Calculates the round-trip time, then updates the
  59. * smoothed round-trip time and the variance (deviation).
  60. * @param ms time in ms since starting the transmission.
  61. */
  62. void stoppedAt(long ms)
  63. {
  64. // Calculate the round-trip time for this packet.
  65. roundTripTime = ms/1000;
  66. // Update our estimators of round-trip time
  67. // and its mean deviation.
  68. double delta = roundTripTime ? smoothedTripTime;
  69. smoothedTripTime += delta/8.0;
  70. deviation += (Math.abs(delta)-deviation)/4.0;
  71. // Recalculate the current timeout.
  72. currentTimeout = minmax(calculateRetransmitTimeout());
  73. }
  74. /**
  75. * Called after a timeout has occurred.
  76. * @return true if it's time to give up,
  77. * false if we can retransmit.
  78. */
  79. boolean isTimeout()
  80. {
  81. currentTimeout *= 2; // next retransmit timeout
  82. retransmissions++;
  83. return retransmissions > MAX_RETRANSMISSIONS;
  84. }
  85. } // RoundTripTimer class
  86. The D
  87. " class exports a D  method like the ones
  88. we have already seen.
  89. // ReliableDatagramSocket class
  90. public class ReliableDatagramSocket
  91. extends DatagramSocket
  92. implements ReliabilityConstants
  93. {
  94. RoundTripTimer roundTripTimer = new RoundTripTimer();
  95. private boolean reinit = false;
  96. private long sendSequenceNo = 0; // send sequence #
  97. private long recvSequenceNo = 0; // recv sequence #
  98. /* anonymous initialization for all constructors */
  99. {
  100. init();
  101. }
  102. /**
  103. * Construct a ReliableDatagramSocket
  104. * @param port Local port: reeive on any interface/address
  105. * @exception SocketException can't create the socket
  106. */
  107. public ReliableDatagramSocket(int port)
  108. throws SocketException
  109. {
  110. super(port);
  111. }
  112. /**
  113. * Construct a ReliableDatagramSocket
  114. * @param port Local port
  115. * @param localAddr local interface address to use
  116. * @exception SocketException can't create the socket
  117. */
  118. public ReliableDatagramSocket
  119. (int port, InetAddress localAddr) throws SocketException
  120. {
  121. super(port, localAddr);
  122. }
  123. /**
  124. * Construct a ReliableDatagramSocket, JDK >= 1.4.
  125. * @param localAddr local socket address to use
  126. * @exception SocketException can't create the socket
  127. */
  128. public ReliableDatagramSocket(SocketAddress localAddr)
  129. throws SocketException
  130. {
  131. super(localAddr);
  132. }
  133. /**
  134. * Overrides DatagramSocket.connect():
  135. * Does the connect, then (re-)initializes
  136. * the statistics for the connection.
  137. * @param dest Destination address
  138. * @param port Destination port
  139. */
  140. public void connect(InetAddress dest, int port)
  141. {
  142. super.connect(dest, port);
  143. init();
  144. }
  145. /**
  146. * Overrides JDK 1.4 DatagramSocket.connect().
  147. * Does the connect, then (re-)initializes
  148. * the statistics for the connection.
  149. * @param dest Destination address
  150. */
  151. public void connect(SocketAddress dest)
  152. {
  153. super.connect(dest);
  154. init();
  155. }
  156. /** Initialize */
  157. private void init()
  158. {
  159. this.roundTripTimer = new RoundTripTimer();
  160. }
  161. /**
  162. * Send and receive reliably,
  163. * retrying adaptively with exponential backoff
  164. * until the response is received or timeout occurs.
  165. * @param sendPacket outgoing request datagram
  166. * @param recvPacket incoming reply datagram
  167. * @exception IOException on any error
  168. * @exception InterruptedIOException on timeout
  169. */
  170. public synchronized void sendReceive
  171. (DatagramPacket sendPacket, DatagramPacket recvPacket)
  172. throws IOException, InterruptedIOException
  173. {
  174. // re-initialize after timeout
  175. if (reinit)
  176. {
  177. init();
  178. reinit = false;
  179. }
  180. roundTripTimer.newPacket();
  181. long start = System.currentTimeMillis();
  182. long sequenceNumber = getSendSequenceNo();
  183. // Loop until final timeout or some unexpected exception
  184. for (;;)
  185. {
  186. // keep using the same sequenceNumber while retrying
  187. setSendSequenceNo(sequenceNumber);
  188. send(sendPacket);// may throw
  189. int timeout =
  190. (int)(roundTripTimer.currentTimeout()*1000.0+0.5);
  191. long soTimeoutStart = System.currentTimeMillis();
  192. try
  193. {
  194. for (;;)
  195. {
  196. // Adjust socket timeout for time already elapsed
  197. int soTimeout = timeout?(int)
  198. (System.currentTimeMillis()?soTimeoutStart);
  199. setSoTimeout(soTimeout);
  200. receive(recvPacket);
  201. long recvSequenceNumber = getRecvSequenceNo();
  202. if (recvSequenceNumber == sequenceNumber)
  203. {
  204. // Got the correct reply:
  205. // stop timer, calculate new RTT values
  206. long ms = System.currentTimeMillis()-start;
  207. roundTripTimer.stoppedAt(ms);
  208. return;
  209. }
  210. }
  211. }
  212. catch (InterruptedIOException exc)
  213. {
  214. // timeout: retry?
  215. if (roundTripTimer.isTimeout())
  216. {
  217. reinit = true;
  218. // rethrow InterruptedIOException to caller
  219. throw exc;
  220. }
  221. // else continue
  222. }
  223. // may throw other SocketException or IOException
  224. } // end re-transmit loop
  225. } // sendReceive()
  226. /**
  227. * @return the last received sequence number;
  228. * used by servers to obtain the reply sequenceNumber.
  229. */
  230. public long getRecvSequenceNo()
  231. {
  232. return recvSequenceNo;
  233. }
  234. /** @return the last sent sequence number */
  235. private long getSendSequenceNo()
  236. {
  237. return sendSequenceNo;
  238. }
  239. /**
  240. * Set the next send sequence number.
  241. * Used by servers to set the reply
  242. * sequenceNumber from the received packet:
  243. *
  244. .  * socket.setSendSequenceNo(socket.getRecvSequenceNo());
  245. *
  246. * @param sendSequenceNo Next sequence number to send.
  247. */
  248. public void setSendSequenceNo(long sendSequenceNo)
  249. {
  250. this.sendSequenceNo = sendSequenceNo;
  251. }
  252. /**
  253. * override for DatagramSocket.receive:
  254. * handles the sequence number.
  255. * @param packet DatagramPacket
  256. * @exception IOException I/O error
  257. */
  258. public void receive(DatagramPacket packet)
  259. throws IOException
  260. {
  261. super.receive(packet);
  262. // read sequence number and remove it from the packet
  263. ByteArrayInputStream bais = new ByteArrayInputStream
  264. (packet.getData(), packet.getOffset(),
  265. packet.getLength());
  266. DataInputStream dis = new DataInputStream(bais);
  267. recvSequenceNo = dis.readLong();
  268. byte[] buffer = new byte[dis.available()];
  269. dis.read(buffer);
  270. packet.setData(buffer,0,buffer.length);
  271. }
  272. /**
  273. * override for DatagramSocket.send:
  274. * handles the sequence number.
  275. * @param packet DatagramPacket
  276. * @exception IOException I/O error
  277. */
  278. public void send(DatagramPacket packet)
  279. throws IOException
  280. {
  281. ByteArrayOutputStreambaos = new ByteArrayOutputStream();
  282. DataOutputStreamdos = new DataOutputStream(baos);
  283. // Write the sequence number, then the user data.
  284. dos.writeLong(sendSequenceNo++);
  285. dos.write
  286. (packet.getData(), packet.getOffset(),
  287. packet.getLength());
  288. dos.flush();
  289. // Construct a new packet with this new data and send it.
  290. byte[]data = baos.toByteArray();
  291. packet = new DatagramPacket
  292. (data, baos.size(), packet.getAddress(),
  293. packet.getPort());
  294. super.send(packet);
  295. }
  296. } // end of ReliableDatagramSocket class
Java代码  
  1. public class ReliableEchoServer implements Runnable
  2. {
  3. ReliableDatagramSocket
  4. socket;
  5. byte[] buffer = new byte[1024];
  6. DatagramPacket recvPacket =
  7. new DatagramPacket(buffer, buffer.length);
  8. ReliableEchoServer(int port) throws IOException
  9. {
  10. this.socket = new ReliableDatagramSocket(port);
  11. }
  12. public void run()
  13. {
  14. for (;;)
  15. {
  16. try
  17. {
  18. // Restore the receive length to the maximum
  19. recvPacket.setLength(buffer.length);
  20. socket.receive(recvPacket);
  21. // Reply must have same seqno as request
  22. long seqno = socket.getRecvSequenceNo();
  23. socket.setSendSequenceNo(seqno);
  24. // Echo the request back as the response
  25. socket.send(recvPacket);
  26. }
  27. catch (IOException exc)
  28. {
  29. exc.printStackTrace();
  30. }
  31. } // for (;;)
  32. } // run()
  33. } // class

UDP支持多播和广播(广播是一种特殊的多播,尽量不使用广播,广播产生更多没必要的网络流量),而TCP只支持单播。一般多播用于服务发现,如jini look up。多播与多次单播相比,好处是减少开销、减小网络流量、减少服务器负载,而且速度更快,并且接受者接收到消息的时间更接近,对于某些场景来说很重要。

多播的缺点是继承了udp,不可靠网络,依赖路由器,安全问题更加复杂。并且多播并不知道多播消息会被哪些接受者接收,也不知道接受者是否接收到,设计协议的时候需要考虑这点。

发送多播消息,发送端可以用MulticastSocket和DatagramSocket,而接收端只能用MulticastSocket。

多播使用场景

(a) Software distribution

(b) Time services

(c) Naming services like

(d) Stock-market tickers, race results, and the like

(e) Database replication

(f) Video and audio streaming: video conferencing, movie shows, etc

(g) Multi-player gaming

(h) Distributed resource allocation

(i) Service discovery.

 
18 设计server需要考虑两点:同时连接的客户数量,每个连接的持续时间。当客户超过一个的时候,我们就要考虑用多线程,这个时候就涉及到线程如何创建、线程运行、线程销毁。服务器端由等待连接的线程和处理连接的线程组成。
服务器模型进化趋势:单线程接收连接、处理连接,无法同时处理多个客户,淘汰;每接收一个请求,创建一个线程对请求处理,可以并发,但是会耗尽服务器资源;采用线程池方式,并进行阀值控制,保护服务器,并进行优雅降级。
关于线程池线程数量的控制,一般是预创建N个线程,当峰值访问来临时,临时创建M个动态线程,一旦访问峰值降下来,再释放动态线程。
连接模型可以分为一个连接一个对话(请求-响应);一个连接多次对话。不同的模型,连接释放的方式不一样。
代码如下
Java代码 
  1. public void processSession(Socket socket)
  2. {
  3. receive(request);
  4. // process request and construct reply, not shown …
  5. send(reply);
  6. // close connection
  7. socket.close();// exception handling not shown
  8. }
Java代码 
  1. void processSession(Socket socket)
  2. {
  3. while (receive(request)) // i.e. while not end-of-stream
  4. {
  5. // process request and construct reply, not shown …
  6. send(reply);
  7. }
  8. // close connection
  9. socket.close();// exception handling not shown
  10. }
 多次对话的连接释放方式,可以根据输入流的返回结果,或者遇到eof来关闭连接。
归结点
(a) On receipt of an end-of-stream when reading the connection.
(b) If the request or the client is deemed invalid.
(c) On detection of a read timeout or idle timeout on the connection.
(d) After writing a reply
 
19 设计客户端,一般需要考虑连接失败和读数据超时。为了减少创建连接的开销,一般还会使用线程池,如rmi。
在请求-响应事务中,一般会采取header_body_trailler的结构。结合使用gathering、scattering io来较少内存和cpu开销
Java代码 
  1. // Initialization - common to both ends
  2. static final int HEADER_LENGTH = 16;
  3. static final int BODY_LENGTH = 480;
  4. static final int TRAILER_LENGTH = 16;
  5. ByteBuffer header = ByteBuffer.allocate(HEADER_LENGTH);
  6. ByteBuffer body = ByteBuffer.allocate(BODY_LENGTH);
  7. ByteBuffer trailer = ByteBuffer.allocate(TRAILER_LENGTH);
  8. ByteBuffer[]
  9. buffers = new ByteBuffer[]
  10. { header, body, trailer };
  11. // sending end - populate the buffers, not shown
  12. long count  = channel.write(buffers);
  13. // repeat until all data sent
  14. // receiving end
  15. long count = channel.read(buffers);
  16. // repeat until all data read
对于浏览器加载页面的过程,由于加载对交互顺序不敏感,所以client可以同时并发多个连接、多个线程并行从服务端获取数据
 
20 jdk为编写并发服务器提供了很好的支持。如Executors提供了线程池,java.util.concurrent.ThreadPoolExecutor.DiscardPolicy提供了阀值控制,ThreadFactory提供了创建线程的方式。
 
21 客户端技术一般来用连接池,如memcache client每个连接某时刻只在一个request-reply事务中。或者多个事务公用一个连接,比如tair client,需要在协议上维护request-reply的匹配关系。
 
22 网络编程的八个谬论
a 网络是可靠的
b 网络没有延迟
c 带宽是无限的
d 网络是安全的
e 网络拓扑不会变
f  只有一个管理员
g 传输开销为0
h  网络是均匀的,网络由不同带宽的节点组成,木桶理论,以最小的那个为带宽。
i 网络io如同磁盘io。网络io更容易出错,不如磁盘稳定
j 和peer的状态是同步的。除非在应用层接收到ack,否则不要假定对方收到你的数据。
k 所有的网络失败都是可以检测的。
l  资源是无限的。其实网络编程涉及的资源包括端口、缓冲都是有限的
m 应用可以无限等待远程服务。任何远程调用都应该设定超时时间。
n 远程服务的响应是及时的
o 有单点失败。在分布式系统中,一般一个host的失败不会引发整个系统的崩溃。除非有一个中心节点。
p 只有一个资源分配器。每个host的资源都可以独立分配。
q 时间是完全统一的
 
 
参考:

java网络编程socket\server\TCP笔记(转)的更多相关文章

  1. 用java网络编程中的TCP方式上传文本文件及出现的小问题

    自己今天刚学java网络编程中的TCP传输,要用TCP传输文件时,自己也是遇到了一些问题,抽空把它整理了一下,供自己以后参考使用. 首先在这个程序中,我用一个客户端,一个服务端,从客户端上传一个文本文 ...

  2. 网络编程Socket之TCP之close/shutdown具体解释(续)

    接着上一篇网络编程Socket之TCP之close/shutdown具体解释 如今我们看看对于不同情况的close的返回情况和可能遇到的一些问题: 1.默认操作的close 说明:我们已经知道writ ...

  3. 从零探索Java网络编程01之 TCP/IP 与 Socket

    最近完成了几项比较简单的项目, 终于是在996里偷了点闲暇时光, 想着来研究研究些啥吧?  一个普通的控制台日志映入了我的眼帘(孽缘呀): (图中使用 SpringBoot 的 log4j 来输出日志 ...

  4. java网络编程socket解析

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

  5. Java网络编程——Socket

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

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

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

  7. 网络编程Socket之TCP

            服务端: 1. 创建 ServerSocket 对象并监听一个端口 2. 调用accept()方法等待客户端的连接(阻塞式) 3. 输入流(记取客户端发送过来的数据) 4. 输出流(响 ...

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

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

  9. python网络编程(Socket、TCP、UDP)

    Socket 是网络编程的一个抽象概念,通常我们用一个Socket表示 "打开了一个网络链接",而打开一个Socket 需要知道目标计算机的IP 地址和端口号,再指定协议类型即可. ...

随机推荐

  1. 《Python学习手册 第五版》 -第18章 参数

    在函数的定义和调用中,参数是使用最多喝最频繁的,本章内容就是围绕函数的参数进行讲解 本章重点内容如下: 1.参数的传递 1)不可变得参数传递 2)可变得参数传递 2.参数的匹配模式 1)位置次序:从左 ...

  2. [Visual Basic]二分查找

    模板 i=1:j=n 'i初值为1,j初值为n Do while i<=j '当i<=j时,通过循环进行查找 m=fix((i+j)/2) '计算出中间元素的下标m If d(m)=key ...

  3. Journal of Proteome Research | Proteomic analysis of Rhizobium favelukesii LPU83 in response to acid stress.(酸胁迫下根瘤菌LPU83(Rhizobium favelukesii)的蛋白质组学分析)(解读人:丑天胜)

    文献名:Proteomic analysis of Rhizobium favelukesii LPU83 in response to acid stress.(酸胁迫下根瘤菌LPU83(Rhizo ...

  4. 关于Quartz .NET(V3.0.7)的简要说明

    目录 0. 任务调度 1. Quartz .NET 1.1 基本概念 1.2 主要接口和对象 2. 使用示例 2.0 准备工作 2.1 每间隔一定时间间隔执行一次任务 2.3 某天的固定时间点执行任务 ...

  5. 阿里云服务器安装Docker

    在阿里云服务器上安装Docker,服务器的系统是CentOS 7.6, 所以可以看官方Docker安装文档:https://docs.docker.com/install/linux/docker-c ...

  6. Andorid 添加MenuPopup

  7. VMware安装Ubutun之SSH为何安装不上之谜

    一把心酸泪,鼻涕泪两行.谁人解我苦中苦,原是SSH安装不上去. 多方找寻,想要寻求解答. 首先我想到一个办法,找到进程,并且狠狠的用RM把它移除掉. NO,这个方法最后竟然不行,文件删了,锁还是获取不 ...

  8. 一夜搞懂 | JVM 类加载机制

    前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 学习导图 一.为什么要学习类加载机制? 今天想跟大家唠嗑唠嗑Java的类加载机制,这是Java的一个很重要的创 ...

  9. coding++:maven根据不同的运行环境,打包不同的配置文件

    1.使用maven管理项目中的依赖,非常的方便.同时利用maven内置的各种插件,在命令行模式下完成打包.部署等操作,可方便后期的持续集成使用. 2.但是每一个maven工程(比如web项目),开发人 ...

  10. setAttribute 方法

    IE8及以下不支持 setAttribute用来修改dom标签上的属性比如(onclick); getAttribute用来获取dom标签上的属性