socket根底
对于java网络编程来说,咱们能接触到的最底层便是socket了。我置信大部分浏览此篇文章的同仁都用过socket。然而,我这篇教程的理念之一就是事无巨细,或者说,啰里啰嗦。因为原本就是一个思维的过程,所以,看官老爷们,就当做意识流格调来看吧(也是因为我文笔较差,因而文章的观赏性可能不是太好,给本人找个理由)。
我在刚学编程的时候,其实是一脸茫然的,尽管也会为屏幕输入“hello world",感到兴奋,然而兴奋之余会感觉,嗯~?,这货色跟我设想的不一样啊,就一个黑屏上输入几个字符,无能啥?这玩意跟网站啥的不沾边啊。包含学习了一些算法、数据结构后,还是感觉,网站啥的,跟我学的不沾边。
起初在学习加入了一个我的项目,波及到网络编程,我的项目简略点说就是树莓派跟pc通过路由器进行数据交换。从那时候起开始应用socket,当然那个时候不求甚解,基本跟学过的网络模型也对不上号。什么三次握手,四次挥手,没用到啊。先不论,干就完了。
秉着这个徐循渐进的学习及思考过程,我就开始了socket编程。
链接
来一段服务端socket示例:
代码 1-1
public class OioServer { private ServerSocket serverSocket; private void openServer(int port) throws IOException { // 1 创立ServerSocket serverSocket = new ServerSocket(); // 2 绑定端口 SocketAddress socketAddress = new InetSocketAddress(port); serverSocket.bind(socketAddress); } @Test public void testOpenServer() throws IOException { OioServer oioServer = new OioServer(); oioServer.openServer(8081); // block Scanner scan = new Scanner(System.in); scan.next(); }}
运行test后,服务器开始监听port
端口了。而后咱们验证下是不是真的在监听,我再window上测试的,所以这里以window为例。首先要关上cmd窗口,而后输出命令
代码 1-2
netstat -aon|findstr "8081"
图1-1
能够看到真的在监听了, 当初尽管开始监听了,然而,真的有客户端从8081进来该怎么办?咱们还须要解决连贯,这个连贯就是咱们的配角socket
.
批改1-1代码如下:
代码1-2
public class OioServer { private ServerSocket serverSocket; private void openServer(int port) throws IOException { // 1 创立ServerSocket serverSocket = new ServerSocket(); // 2 绑定端口 SocketAddress socketAddress = new InetSocketAddress(port); serverSocket.bind(socketAddress); } @Test public void testOpenServer() throws IOException { OioServer oioServer = new OioServer(); oioServer.openServer(8081); Socket socket = oioServer.listenAccept(); }}
此时,服务端就运行有客户端进来连贯了。而后咱们再写一个客户端。
代码 1-3
public class OioClient{ public Socket connect(String host, int port) throws IOException { Socket socket = new Socket(); socket.connect(new InetSocketAddress(host, port)); return socket } @Test public void testClient() throws IOException, InterruptedException { OioClient oioServer = new OioClient(); oioServer.connect("127.0.0.1", 8081); // block Scanner scan = new Scanner(System.in); scan.next(); }}
运行test,为例不让test退出,咱们用规范出入block住test线程。记住,当初咱们服务端还在监听,我服务端和客户端都跑在同一台pc上。成果如图
图1-2
能够看到第二行本地地址是127.0.0.1:6283
近程地址是127.0.0.1:8081
,那咱们是不是能够猜到,这个TCP连贯是客户端的,客户端的IP是6283
,咱们尽管没指定,然而零碎会给咱们随机调配一个可用的端口,不信能够试一下,下次可能就不一样了。
牵强附会,第三行就是咱们服务端的TCP连贯。
那么咱们是不是能够有一个这样的论断:socket
其实就是一个TCP连贯的封装(当然也能够是UDP,这里不做探讨)?或者socket的上层是TCP/IP层?
到当初咱们大略晓得了socket跟TCP的分割,既跟网络模型的分割。
有了TCP链接,咱们就能够开始传输数据了。很多网上例子是,简历socket连贯后,客户端给服务器发送数据,而后服务器接收数据并回复。然而请不要误会,过程不肯定全副是这样的。咱们客户端和服务端建设链接后,两边都失去一个socket
,这两个socket
是等价的。如果你对TCP有理解的话,肯定会晓得TCP的四次挥手,网上对于四次挥手的图大略也都是下图这个样子:
图1-3
然而呢,四次挥手同样能够由服务端发动。因而,就算是在TCP层,两个socket的是等价的。
通信
咱们失去沉闷的socket后,就能够对socket进行读写操作了。既然socket没什么区别,那咱们能够无差别看待socket。咱们来写socket读写取的办法:
代码1-4
public class SocketUtils { /** * 从socket中读数据 */ public static String read(Socket socket) { try { InputStream inputStream = socket.getInputStream(); byte[] bytes = new byte[1024]; int len; StringBuilder sb = new StringBuilder(); while ((len = inputStream.read(bytes)) != -1) { //留神指定编码格局,发送方和接管方肯定要对立,倡议应用UTF-8 sb.append(new String(bytes, 0, len, "UTF-8")); } return sb.toString(); } catch (IOException e) { e.printStackTrace(); return null; } } /** * 往socket中写数据 */ public static void write(Socket socket, String response) { try { OutputStream outputStream = socket.getOutputStream(); outputStream.write(response.getBytes("UTF-8")); outputStream.flush(); socket.shutdownOutput(); } catch (IOException e) { e.printStackTrace(); } }}
下面代码以入参的局势将socket传入,而后就行读写,留神,咱们这两个并没有调用办法socket.close
,也就是说socket能够反复读写数据,而网上大部分教程间接会吧socket给敞开,造成初学者认为每次读写玩就得敞开socket的错觉。
在办法read
中,依据(len = inputStream.read(bytes)) != -1
来判断是否读取完数据。而写入数据端怎么通知接收端它实现了写入呢?咱们能够用socket.shutdownOutput()
办法。
好,接下来咱们就来测试下发送与接收数据。
代码1-4
public class OioServer { ... @Test public void testOpenServer() throws IOException { OioServer oioServer = new OioServer(); oioServer.openServer(8081); Socket socket = oioServer.listenAccept(); SocketUtils.write(socket, "Can you hear me?"); String msg = SocketUtils.read(socket); System.out.println(msg); // block Scanner scan = new Scanner(System.in); scan.next(); }}
代码1-5
public class OioClient { ... @Test public void testClient() throws IOException, InterruptedException { OioClient oioServer = new OioClient(); Socket socket = oioServer.connect("127.0.0.1", 8081); String msg = SocketUtils.read(socket); System.out.println(msg); SocketUtils.write(socket, "Yes, I can hear you!"); // block Scanner scan = new Scanner(System.in); scan.next(); }}
先执行testOpenServer()
再执行testClient()
。就会实现对话。当然咱们能够反复调SocketUtils.read
和 SocketUtils.write
进行通信,只有两边socket不敞开。
小结
此篇文章总结了Socket的一些应用,包含服务器启动,socket建设,并证实了socket的等价性