java基础-chapter18(网络编程)
网络编程:在网络通信协议下,不同计算机上运行的程序,进行的数据传输
Java中 BS(Browser/Server)架构有以下优点和缺点:
优点:
-
跨平台性: 可在各种操作系统和设备上运行,只需具备标准Web浏览器即可。
-
易于部署: 不需要在客户端安装特定软件,部署和更新简便。
-
集中式管理: 便于集中管理和维护,更新、安全性和性能优化更便捷。
-
安全性: 相对于传统客户端/服务器架构更容易实现安全,减少一些安全风险。
-
易于扩展: 在服务器端实现大部分业务逻辑,扩展性能和容量相对容易。
缺点:
-
网络依赖性: 对网络稳定性要求较高,可能会影响用户体验。
-
性能: 每次操作都需要与服务器交互,性能可能稍逊于客户端/服务器架构。
-
浏览器兼容性: 需要额外工作来确保不同浏览器上的兼容性。
-
开发复杂性: 需同时开发客户端界面和服务器端逻辑,增加开发复杂度。
-
安全性挑战: 虽相对容易实现安全,但仍需注意安全风险,如跨站脚本攻击等。
Java中CS(Client/Server)架构有以下优点和缺点:
优点:
-
性能: CS架构通常比BS架构性能更好,因为大部分业务逻辑和数据处理在客户端完成,减少了与服务器的交互次数。
-
灵活性: 客户端独立运行,不依赖网络连接,可在没有网络或网络差的情况下执行操作。
-
功能丰富: 客户端可利用本地资源和功能,实现更丰富的功能。
-
数据隔离: 客户端可缓存数据,减少对服务器的请求,提高整体效率。
缺点:
-
平台限制: 需要特定的客户端软件,增加跨平台开发和维护成本。
-
部署和更新困难: 部署和更新客户端软件相对复杂,尤其在大规模部署时面临挑战。
-
安全性: 客户端数据易被篡改和窃取,需要额外安全措施。
-
维护成本高: 维护和更新客户端软件成本较高。
-
资源占用: 客户端软件可能占用系统资源,影响设备性能。
网络编程三要素
-
IP地址: IP地址是用于唯一标识网络中设备(计算机、路由器等)的地址。在Internet上,IP地址采用IPv4或IPv6协议进行编址。IPv4地址通常以点分十进制表示,如
192.168.0.1
,而IPv6地址通常以十六进制表示,如2001:0db8:85a3:0000:0000:8a2e:0370:7334
。 -
端口号: 端口号是用于标识网络中不同进程(应用程序)的数字。端口号范围从0到65535,其中0到1023是知名端口,用于常见的服务,比如HTTP服务使用端口号80。端口号大于1023的是动态端口,用于客户端与服务器之间的临时通信。
-
协议: 协议定义了数据在网络上传输的规则和格式。常见的网络协议包括TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据报协议)。TCP提供可靠的、面向连接的数据传输,而UDP则提供了无连接的、不可靠的数据传输。
这三个要素是网络编程的基础,通过它们可以实现设备之间的通信和数据交换。
UDP(User Datagram Protocol)和TCP(Transmission Control Protocol)都是在网络通信中常用的两种协议,它们有一些重要的区别:
-
可靠性:
- TCP 提供可靠的、面向连接的通信。它确保数据按照发送的顺序到达目的地,而且会检测和重传丢失的数据包。
- UDP 是无连接的,并且不保证数据包的可靠性或顺序。数据发送之后,不会等待确认,也不会进行重传。
-
传输效率:
- TCP 由于提供了可靠性保证,因此会有较多的开销,包括连接建立和维护、数据包的确认和重传等,可能会导致一些额外的延迟。
- UDP 相对于TCP来说,更加轻量级,没有建立连接的开销,也不需要进行数据确认和重传,因此传输效率更高。
-
应用场景:
- TCP 适用于需要可靠传输的场景,如文件传输、网页浏览等,对数据传输的完整性要求较高的应用。
- UDP 适用于实时性要求较高的场景,如音频、视频流传输、在线游戏等,对数据传输的实时性要求较高,而且可以容忍一定程度的丢包。
-
连接性:
- TCP 是面向连接的,通信前需要建立连接,通信结束后需要释放连接。
- UDP 是无连接的,每个数据包都是独立的,发送方和接收方之间没有明确的连接关系。
在Java中,你可以使用java.net
包中的DatagramSocket
来实现UDP通信,而使用Socket
和ServerSocket
类来实现TCP通信。UDP通信更适用于实时性要求高、数据量较小且对可靠性要求不高的场景,而TCP通信则更适用于需要可靠性保证的场景。
UDP发送数据
public class SendMessageDemo1 {public static void main(String[] args) throws IOException {//创建DatagramSocket对象DatagramSocket ds = new DatagramSocket();//打包数据String str = "你好,idea";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 10010;DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);//发送数据ds.send(dp);//释放资源ds.close();}
}
UDP接收数据
public class ReceiveMessageDemo2 {public static void main(String[] args) throws IOException {//接收数据//创建DatagramSocket对象//在接收的时候,一定要绑定端口,而且绑定的端口一定要和发送的端口保持一致DatagramSocket ds = new DatagramSocket(10010);//接收数据byte [] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);//该方法是阻塞的 程序执行到这会等待 直到发送端发送消息ds.receive(dp);//解析数据包byte[] data = dp.getData();int len = dp.getLength();InetAddress address = dp.getAddress();int port = dp.getPort();System.out.println("接收到的数据:"+new String(data,0,len));System.out.println("数据来源"+address+"设备的"+port+"端口发出");ds.close();}
}
聊天室练习
UDP发送数据: 数据来自于键盘录入,直到输入的数据是886,发送数据结束
public class SendTest1 {/*UDP发送数据: 数据来自于键盘录入,直到输入的数据是886,发送数据结束UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收*/public static void main(String[] args) throws IOException {Scanner sc = new Scanner(System.in);//创建DatagramSocket对象DatagramSocket ds = new DatagramSocket();InetAddress address = InetAddress.getByName("127.0.0.1"); //获取IPint port = 10086; //定义端口号byte[] bytes = new byte[1024];while (true){System.out.print("发送消息:");String s = sc.next();bytes = s.getBytes();DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);ds.send(dp);if (s.equals("886")){break;}}ds.close();}
}
UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收
public class ReceiveTest2 {/*UDP发送数据: 数据来自于键盘录入,直到输入的数据是886,发送数据结束UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收*/public static void main(String[] args) throws IOException {DatagramSocket ds = new DatagramSocket(10086);byte bytes [] = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);while (true){ds.receive(dp);//解析数据byte[] data = dp.getData(); //解析数据int len = dp.getLength(); //解析数组长度InetAddress address = dp.getAddress(); //解析数据int port = dp.getPort(); //解析端口号System.out.println("接收到的数据:"+new String(data,0,len));System.out.println("数据来源:"+address+" 由"+port+"端口号发出");}}
}