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 时间是完全统一的
参考:
http://www.blogjava.net/nokiaguy/archive/2009/06/01/279436.html
http://blog.csdn.net/lin49940/article/details/4382303

转载于:https://www.cnblogs.com/wzhanke/p/4817719.html

java网络编程socket\server\TCP笔记(转)相关推荐

  1. java网络编程,通过TCP,Socket实现多对一的局域网聊天室

    java网络编程,通过TCP,Socket实现多对一的局域网聊天室 可以实现多个客户端连接服务器,服务器接收到信息就会把信息广播到所有的客户端 这是服务器端的代码 View Code import j ...

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

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

  3. Java网络编程 Socket、ServerSocket 详解,方法介绍及完整代码示例

    Java网络编程 Socket.ServerSocket 详解,方法介绍及完整代码示例 概念 什么是网络编程? 网络编程是指编写运行在多个设备(计算机)的程序,这些设备通过网络连接起来.当这些通过网络 ...

  4. 迈入JavaWeb第一步,Java网络编程基础,TCP网络编程URL网络编程等

    文章目录 网络编程概述 网络通信要素 要素一IP和端口号 要素二网络协议 TCP网络编程 UDP网络编程 URL网络编程 Java网络编程基础 网络编程概述 Java是Internet上的语言,它从语 ...

  5. java 中的网络编程(Socket、TCP三次握手四次挥手、TCP/UDP/URL)

    文章目录 前言 一.网络编程概述 二.网络通信要素概述 1.如何实现网络中的主机互相通信 2.网络通信协议 3.IP和端口号 4.InetAddress类 5.网络协议 6.TCP/IP协议簇 7.T ...

  6. 【java网络编程】用TCP socket实现多线程图片上传

    单线程上传 服务端: 客户端: 多线程上传 修改服务端: 修改客户端 单线程上传 服务端: public static void main(String[] args) {try ( // 创建一个S ...

  7. Java网络编程——Socket 编程

    Socket 编程 Socket编程是在TCP/IP上的网络编程,但是Socket在上述模型的什么位置呢.这个位置被一个天才的理论家或者是抽象的计算机大神提出并且安排出来 我们可以发现Socket就在 ...

  8. Java网络编程 韩顺平 自学笔记

    这里写目录标题 网络编程 网络通信 网络 ip地址 ipv4地址分类 域名 端口号 网络通信协议 TCP和UDP TCP协议:传输控制协议 UDP协议 InetAddress类 相关方法 代码示例 S ...

  9. 关于JAVA网络编程UDP和TCP(上)

    对于JAVA的网络编程我们又称之为socket编程.首先,网络编程,顾名思义,要涉及到网络,其中网络协议是必不可少的对于我们而言,一个重要的网络协议是大家要会的:TCP/IP协议,udp协议. 一.网 ...

最新文章

  1. jmeter对需要登录的接口进行性能测测试
  2. jpa 实体图查询_JPA实体图
  3. js将base64做UrlEncode转码
  4. C++王者之路 | C++的sizeof 与C语言的sizeof
  5. 每秒处理10万订单的支付架构
  6. centos安装最新的visual studio code并设置中文
  7. 网线连接威纶触摸屏失败的解决方法
  8. 二维六点对称格式matlab,热传导方程求解的程序
  9. SeaweedFS使用小结
  10. 如何查看某公司主体下挂了哪些公众号?
  11. Memory Limited Persistent Message Queue
  12. 1971旗舰cpu intel_这就是近年来Intel最良心CPU!我彻底服了
  13. 玩转Linux的下Ip计算器(图文)
  14. 用C语言求一元二次方程的解
  15. 结构健康监测平台发展现状
  16. win10家庭版没有本地组策略编辑器
  17. WIN7创建系统映像失败:卷影复制服务操作失败 的解决办法
  18. 快速排序两种最基本思路
  19. 电销企业外呼系统如何选最合适?
  20. 全志A31下5M的CMOSCamera移植修改记录表

热门文章

  1. Launcher3源码分析 — 将Workspace的数据与界面绑定
  2. ipad手写笔什么牌子好?最好用的电容笔
  3. 自定义脚本实践-------有谱* 自动播放
  4. Maven中scope标签的作用
  5. 极客日报:华为诉争“鸿蒙HongMeng”商标再被驳回;比尔盖茨夫妇正式离婚;iOS 15“查找”新功能,关机也能用
  6. 【C语言】常用公式函数使用
  7. 次世代3A游戏开发将飙至1.5亿美元,游戏时长将更短
  8. #Paper Reading# Language Models are Few-Shot Learner
  9. Unity制作二次元卡通渲染角色材质——1、资源分析
  10. 理光有邮件服务器吗,理光复合机扫描怎么设置? 理光复合机扫描到邮件的设置方法...