Socket 编程学习篇
接上一篇Socket编程学习(一)内容
服务端优化
在上面的例子中,服务端仅仅只是接受了一个Socket请求,并处理了它,然后就结束了。但是在实际的开发中,一个Socket服务往往需要服务大量的Socket请求,那么就不能再服务完一个Socket的时候就关闭了,这时候就可以采用死循环的方式来接收请求。
循环方式
服务端
package socket.服务端优化.循环方式;
import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;
public class SocketServer {
public static void main(String args[]) throws IOException { int port = 55533; ServerSocket server = new ServerSocket(port); System.out.println("server将一直等待连接的到来"); while (true) { Socket socket = server.accept(); InputStream is = socket.getInputStream(); byte[] bytes = new byte[1024]; int len; StringBuilder sb = new StringBuilder(); while ((len = is.read(bytes)) != -1) { sb.append(new String(bytes, 0, len, "UTF-8")); } System.out.println("get message from client: " + sb); is.close(); socket.close(); } } }
|
这种一般也是新手写法,但是能够循环处理多个Socket请求,不过当一个请求的处理比较耗时的时候,后面的请求将会被阻塞,所以一般都是采用多线程的方式来处理Socket,即每一个Socket请求时,就创建一个线程来处理它。
不过在实际开发中,创建的线程会交给线程池来处理,为了:线程复用,创建线程耗时,回收线程慢。
为了防止短时间内高并发,指定线程池大小,超过指定数量线程的任务将被等待,防止短时间内创建大量线程导致资源耗尽,服务挂掉。
多线程线程池方式
服务端
package socket.服务端优化.多线程方式;
import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
public class SocketServer { public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(55533); System.out.println("server将一直等待连接的到来"); ExecutorService threadPool = Executors.newFixedThreadPool(100);
while (true) { Socket socket = server.accept();
Runnable runnable = () -> { try { InputStream is = socket.getInputStream(); byte[] bytes = new byte[1024]; int len; StringBuilder sb = new StringBuilder(); while ((len = is.read(bytes)) != -1) { sb.append(new String(bytes, 0, len, "UTF-8")); } System.out.println("get message from client: " + sb); is.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } }; threadPool.submit(runnable); } } }
|
使用线程池的方式,算是一种成熟的方式,可以应用在生产中。
ServerSocket有以下3个属性:
- SO_TIMEOUT:表示等待客户连接的超时时间。一般不设置,会持续等待。
- SO_REUSEADDR:表示是否允许重用服务器所绑定的地址。一般不设置。
- SO_RCVBUF:表示接收数据的缓冲区的大小。一般不设置。
在使用TCP通信传输信息时,更多的是使用对象的形式来传输,可以使用ObjectOutputStream
对象序列化流来传递对象,比如:
ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream()); User user = new User("admin", "123); os.writeObject(user);
|
本节内容参考于码农家园,在此致谢~~~
本节示例代码仓库