编写一个网络应用程序,有客户端和服务器端,客户端向服务器发送一个字符串,服务器收到该字符串后将其打印到命令行上,然后向客户端返回该字符串的长度,最后,客户端输出输出服务器端返回的该字符串的长度,分别用TCP和UDP两种方式去实现?
tcp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 package com.java.interview.socket;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;public class TCPServer { public static void main (String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(65000 ); while (true ){ Socket socket = serverSocket.accept(); new LengthCalculator(socket).start(); } } } package com.java.interview.socket;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;public class TCPClient { public static void main (String[] args) throws IOException { Socket socket = new Socket("127.0.0.1" ,65000 ); OutputStream os = socket.getOutputStream(); InputStream is = socket.getInputStream(); os.write(new String("hello world" ).getBytes()); int ch = 0 ; byte [] buff = new byte [1024 ]; ch = is.read(buff); String content = new String(buff,0 ,ch); System.out.println(content); is.close(); os.close(); socket.close(); } } package com.java.interview.socket;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;public class LengthCalculator extends Thread { private Socket socket; public LengthCalculator (Socket socket) { this .socket = socket; } @Override public void run () { try { OutputStream os = socket.getOutputStream(); InputStream is = socket.getInputStream(); int ch = 0 ; byte [] buff = new byte [1024 ]; ch = is.read(buff); String content = new String(buff,0 ,ch); System.out.println(content); os.write(String.valueOf(content.length()).getBytes()); is.close(); os.close(); socket.close(); }catch (IOException e){ e.printStackTrace(); } } }
udp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 package com.java.interview.socket;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.SocketException;public class UDPServer { public static void main (String[] args) throws IOException { DatagramSocket socket = new DatagramSocket(65001 ); byte [] buff = new byte [100 ]; DatagramPacket packet = new DatagramPacket(buff,buff.length); socket.receive(packet); byte [] data = packet.getData(); String content = new String(data,0 ,packet.getLength()); System.out.println(content); byte [] sendedContent = String.valueOf(content.length()).getBytes(); DatagramPacket packetToClient = new DatagramPacket(sendedContent,sendedContent.length, packet.getAddress(),packet.getPort()); socket.send(packetToClient); } } package com.java.interview.socket;import java.io.IOException;import java.net.*;public class UDPClient { public static void main (String[] args) throws IOException { DatagramSocket socket = new DatagramSocket(); byte [] buf = "hello world" .getBytes(); InetAddress address = InetAddress.getByName("127.0.0.1" ); DatagramPacket packet = new DatagramPacket(buf,buf.length,address,65001 ); socket.send(packet); byte [] data = new byte [100 ]; DatagramPacket receivedPacket = new DatagramPacket(data,data.length); socket.receive(receivedPacket); String content = new String(receivedPacket.getData(),0 ,receivedPacket.getLength()); System.out.println(content); } }
Socket原理 1、什么是Socket 在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信 的一种约定 或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据 socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。 我的理解就是Socket就是该模式的一个实现:即socket是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。 Socket()函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。
2、网络中进程如何通信 既然Socket主要是用来解决网络通信的,那么我们就来理解网络中进程是如何通信的。
2.1、本地进程间通信 a、消息传递(管道、消息队列、FIFO) b、同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)?【不是很明白】 c、共享内存(匿名的和具名的,eg:channel) d、远程过程调用(RPC)
2.2、网络中进程如何通信 我们要理解网络中进程如何通信,得解决两个问题: a、我们要如何标识一台主机,即怎样确定我们将要通信的进程是在那一台主机上运行。 b、我们要如何标识唯一进程,本地通过pid标识,网络中应该怎样标识? 解决办法: a、TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机 b、传输层的“协议+端口”可以唯一标识主机中的应用程序(进程),因此,我们利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互
3、Socket怎么通信 现在,我们知道了网络中进程间如何通信,即利用三元组【ip地址,协议,端口】可以进行网络间通信了,那我们应该怎么实现了,因此,我们socket应运而生,它就是利用三元组解决网络通信的一个中间件工具,就目前而言,几乎所有的应用程序都是采用socket,如UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰)。 Socket通信的数据传输方式,常用的有两种: a、SOCK_STREAM:表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢。常见的 http 协议就使用 SOCK_STREAM 传输数据,因为要确保数据的正确性,否则网页不能正常解析。 b、SOCK_DGRAM:表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为 SOCK_DGRAM 所做的校验工作少,所以效率比 SOCK_STREAM 高。 例如:QQ 视频聊天和语音聊天就使用 SOCK_DGRAM 传输数据,因为首先要保证通信的效率,尽量减小延迟,而数据的正确性是次要的,即使丢失很小的一部分数据,视频和音频也可以正常解析,最多出现噪点或杂音,不会对通信质量有实质的影响
欢迎访问 chenyawei 的博客, 若有问题或者有好的建议欢迎留言,笔者看到之后会及时回复。 评论点赞需要github账号登录,如果没有账号的话请点击 github 注册, 谢谢 !
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !