宁波网站建设熊掌号,百度链接提交工具,可以加外链的网站,做网站建设工资多少文章目录 Day20 网络编程学习目标1 软件结构2 网络编程三要素2.1 IP地址和域名1、IP地址2、域名3、InetAddress类 2.2 端口号2.3 网络通信协议1、OSI参考模型和TCP/IP参考模型2、UDP协议3、TCP协议 2.4 Socket编程 3 UDP网络编程3.1 DatagramSocket和DatagramPacket1、Datagram… 文章目录 Day20 网络编程学习目标1 软件结构2 网络编程三要素2.1 IP地址和域名1、IP地址2、域名3、InetAddress类 2.2 端口号2.3 网络通信协议1、OSI参考模型和TCP/IP参考模型2、UDP协议3、TCP协议 2.4 Socket编程 3 UDP网络编程3.1 DatagramSocket和DatagramPacket1、DatagramSocket2、DatagramPacket类 3.2 开发步骤3.3 通信模型3.4 演示发送和接收消息1、发送端示例代码2、接收端示例代码 4 TCP网络编程4.1 ServerSocket和Socket1、ServerSocket类2、Sokcet类 4.2 开发步骤4.3 通信模型4.4 演示单个客户端与服务器单次通信1、服务器端示例代码2、客户端示例代码 4.5 演示多个客户端与服务器之间的多次通信1、服务器端示例代码2、客户端示例代码 Day20 网络编程
学习目标 了解网络通信协议参考模型 能够理解IP地址和端口号的作用 能够在程序中表示IP地址和端口号 能够说出TCP和UDP网络协议的区别 了解基于Socket的TCP网络编程 了解基于Socket的UDP网络编程
1 软件结构
C/S结构 全称为Client/Server结构是指客户端和服务器结构。常见程序有、红蜘蛛等软件。 B/S结构 全称为Browser/Server结构是指浏览器和服务器结构。常见浏览器有IE、谷歌、火狐等。 两种架构各有优势但是无论哪种架构都离不开网络的支持。网络编程就是在一定的协议下实现两台计算机的通信的程序。
2 网络编程三要素
2.1 IP地址和域名
1、IP地址
IP地址指互联网协议地址Internet Protocol Address俗称IP。IP地址用来给一个网络中的计算机设备做唯一的编号。假如我们把“个人电脑”比作“一台电话”的话那么“IP地址”就相当于“电话号码”。
IP地址分类方式一 IPv4是一个32位的二进制数通常被分为4个字节表示成a.b.c.d 的形式例如192.168.65.100 。其中a、b、c、d都是0~255之间的十进制整数那么最多可以表示42亿个。 IPv6由于互联网的蓬勃发展IP地址的需求量愈来愈大但是网络地址资源有限使得IP的分配越发紧张。 为了扩大地址空间拟通过IPv6重新定义地址空间采用128位地址长度每16个字节一组分成8组十六进制数表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789号称可以为全世界的每一粒沙子编上一个网址这样就解决了网络地址资源数量不够的问题。IPv4和IPv6地址格式不相同因此在很长一段时间里互联网中出现IPv4和IPv6长期共存的局面。2012年6月6日国际互联网协会举行了世界IPv6启动纪念日这一天全球IPv6网络正式启动。多家知名网站如Google、Facebook和Yahoo等于当天全球标准时间0点北京时间8点整开始永久性支持IPv6访问。2018年6月三大运营商联合阿里云宣布将全面对外提供IPv6服务并计划在2025年前助推中国互联网真正实现“IPv6 Only”。 7月百度云制定了中国的IPv6改造方案。8月3日工信部通信司在北京召开IPv6规模部署及专项督查工作全国电视电话会议中国将分阶段有序推进规模建设IPv6网络实现下一代互联网在经济社会各领域深度融合。
IP地址分类方式二
公网地址( 万维网使用)和 私有地址( 局域网使用)。192.168.开头的就是私有址址范围即为192.168.0.0–192.168.255.255专门为组织机构内部使用
常用命令
查看本机IP地址在控制台输入
ipconfig检查网络是否连通在控制台输入
ping 空格 IP地址
ping 220.181.57.216特殊的IP地址
本地回环地址(hostAddress)127.0.0.1主机名(hostName)localhost
2、域名
因为IP地址数字不便于记忆因此出现了域名域名容易记忆当在连接网络时输入一个主机的域名后域名服务器(DNS)负责将域名转化成IP地址这样才能和主机建立连接。 ------- 域名解析 在浏览器中输入www . qq .com 域名操作系统会先检查自己本地的hosts文件C:\Windows\System32\drivers\etc\hosts是否有这个网址映射关系如果有就先调用这个IP地址映射完成域名解析。如果hosts里没有这个域名的映射则查找本地DNS解析器缓存是否有这个网址映射关系如果有直接返回完成域名解析。如果hosts与本地DNS解析器缓存都没有相应的网址映射关系首先会找TCP/ip参数中设置的首选DNS服务器在此我们叫它本地DNS服务器此服务器收到查询时如果要查询的域名包含在本地配置区域资源中则返回解析结果给客户机完成域名解析此解析具有权威性。如果要查询的域名不由本地DNS服务器区域解析但该服务器已缓存了此网址映射关系则调用这个IP地址映射完成域名解析此解析不具有权威性。如果本地DNS服务器本地区域文件与缓存解析都失效则根据本地DNS服务器的设置是否设置转发器进行查询如果未用转发模式本地DNS就把请求发至13台根DNS根DNS服务器收到请求后会判断这个域名(.com)是谁来授权管理并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后将会联系负责.com域的这台服务器。这台负责.com域的服务器收到请求后如果自己无法解析它就会找一个管理.com域的下一级DNS服务器地址(http://qq.com)给本地DNS服务器。当本地DNS服务器收到这个地址后就会找http://qq.com)域服务器重复上面的动作进行查询直至找到www . qq .com主机。如果用的是转发模式此DNS服务器就会把请求转发至上一级DNS服务器由上一级服务器进行解析上一级服务器如果不能解析或找根DNS或把转请求转至上上级以此循环。不管是本地DNS服务器用是是转发还是根提示最后都是把结果返回给本地DNS服务器由此DNS服务器再返回给客户机。
3、InetAddress类
InetAddress类主要表示IP地址两个子类Inet4Address、Inet6Address。
Internet上的主机有两种方式表示地址
域名(hostName)www.atguigu.comIP 地址(hostAddress)202.108.35.210
lInetAddress 类没有提供公共的构造器而是提供 了 如下几个 静态方法来获取InetAddress 实例
public static InetAddress getLocalHost()public static InetAddress getByName(String host)public static InetAddress getByAddress(byte[] addr)
InetAddress 提供了如下几个常用的方法
public String getHostAddress() 返回 IP 地址字符串以文本表现形式。public String getHostName() 获取此 IP 地址的主机名
package com.atguigu.ip;import java.net.InetAddress;
import java.net.UnknownHostException;import org.junit.Test;public class TestInetAddress {Testpublic void test01() throws UnknownHostException{InetAddress localHost InetAddress.getLocalHost();System.out.println(localHost);}Testpublic void test02()throws UnknownHostException{InetAddress atguigu InetAddress.getByName(www.atguigu.com);System.out.println(atguigu);}Testpublic void test03()throws UnknownHostException{
// byte[] addr {112,54,108,98};byte[] addr {(byte)192,(byte)168,24,56};InetAddress atguigu InetAddress.getByAddress(addr);System.out.println(atguigu);}
}2.2 端口号
网络的通信本质上是两个进程应用程序的通信。每台计算机都有很多的进程那么在网络通信时如何区分这些进程呢
如果说IP地址可以唯一标识网络中的设备那么端口号就可以唯一标识设备中的进程应用程序了。
端口号用两个字节表示的整数它的取值范围是0~65535。 公认端口0~1023。被预先定义的服务通信占用如HTTP80FTP21Telnet23注册端口1024~49151。分配给用户进程或应用程序。如Tomcat8080MySQL3306Oracle1521。动态/ 私有端口49152~65535。
如果端口号被另外一个服务或应用所占用会导致当前程序启动失败。
2.3 网络通信协议
1、OSI参考模型和TCP/IP参考模型 **网络通信协议**通过计算机网络可以使多台计算机实现连接位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中这些连接和通信的规则被称为网络通信协议它对数据的传输格式、传输速率、传输步骤等做了统一规定通信双方必须同时遵守才能完成数据交换。 TCP/IP协议 传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol)是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议并采用了4层的分层模型每一层都呼叫它的下一层所提供的协议来完成自己的需求。 上图中OSI参考模型模型过于理想化未能在因特网上进行广泛推广。 TCP/IP参考模型(或TCP/IP协议)事实上的国际标准。
TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层每层分别负责不同的通信功能。 链路层链路层是用于定义物理传输通道通常是对某些网络连接设备的驱动协议例如针对光纤、网线提供的驱动。网络层网络层是整个TCP/IP协议的核心它主要用于将传输的数据进行分组将分组数据发送到目标计算机或者网络。而IP协议是一种非常重要的协议。IPinternet protocal又称为互联网协议。IP的责任就是把数据从源传送到目的地。它在源地址和目的地址之间传送一种称之为数据包的东西它还提供对数据大小的重新组装功能以适应不同网络对包大小的要求。传输层主要使网络程序进行通信在进行网络通信时可以采用TCP协议也可以采用UDP协议。TCPTransmission Control Protocol协议即传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。UDP(User Datagram Protocol用户数据报协议)是一个无连接的传输层协议、提供面向事务的简单不可靠的信息传送服务。应用层主要负责应用程序的协议例如HTTP协议、FTP协议、SNMP简单网络管理协议、SMTP简单邮件传输协议和POP3Post Office Protocol 3的简称,即邮局协议的第3个版等。
而通常我们说的TCP/IP协议其实是指TCP/IP协议族因为该协议家族的两个最核心协议TCP传输控制协议和IP网际协议为该家族中最早通过的标准所以简称为TCP/IP协议。
2、UDP协议
UDP用户数据报协议(User Datagram Protocol)它是非面向连的不可靠的无连接通信协议即在数据传输时数据的发送端和接收端不建立逻辑连接。简单来说当一台计算机向另外一台计算机发送数据时发送端不会确认接收端是否存在就会发出数据同样接收端在收到数据时也不会向发送端反馈是否收到数据。
由于使用UDP协议消耗资源小通信效率高所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议因为这种情况即使偶尔丢失一两个数据包也不会对接收结果产生太大影响。
但是在使用UDP协议传送数据时由于UDP的面向无连接性不能保证数据的完整性因此在传输重要数据时不建议使用UDP协议。 大小限制的数据被限制在64kb以内超出这个范围就不能发送了。 数据报(Datagram)网络传输的基本单位
UDP用户数据报协议(User Datagram Protocol)是一种面向非连接的协议面向非连接指的是在正式通信前不必与对方先建立连接不管对方状态就直接发送至于对方是否可以接收到这些数据内容UDP协议无法控制因此说UDP协议是一种不可靠的协议。无连接的好处就是快省内存空间和流量因为维护连接需要创建大量的数据结构。UDP会尽最大努力交付数据但不保证可靠交付没有TCP的确认机制、重传机制如果因为网络原因没有传送到对端UDP也不会给应用层返回错误信息。
UDP协议是面向数据报文的信息传送服务。UDP在发送端没有缓冲区对于应用层交付下来的报文在添加了首部之后就直接交付于ip层不会进行合并也不会进行拆分而是一次交付一个完整的报文。比如我们要发送100个字节的报文我们调用一次send()方法就会发送100字节接收方也需要用receive()方法一次性接收100字节不能使用循环每次获取10个字节获取十次这样的做法。
UDP协议没有拥塞控制所以当网络出现的拥塞不会导致主机发送数据的速率降低。虽然UDP的接收端有缓冲区但是这个缓冲区只负责接收并不会保证UDP报文的到达顺序是否和发送的顺序一致。因为网络传输的时候由于网络拥塞的存在是很大的可能导致先发的报文比后发的报文晚到达。如果此时缓冲区满了后面到达的报文将直接被丢弃。这个对实时应用来说很重要比如视频通话、直播等应用。
因此UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境数据报大小限制在64K以下。
3、TCP协议
TCP传输控制协议 (Transmission Control Protocol)。它是面向连接的可靠的通信协议即传输数据之前在发送端和接收端建立逻辑连接然后再传输数据它提供了两台计算机之间可靠无差错的数据传输。是一种面向连接的、可靠的、基于字节流的传输层的通信协议可以连续传输大量的数据。类似于打电话的效果。
TCP协议负责收集这些数据信息包并将其按适当的次序放好传送在接收端收到后再将其正确的还原。TCP协议保证了数据包在传送中准确无误。TCP协议使用重发机制当一个通信实体发送一个消息给另一个通信实体后需要收到另一个通信实体确认信息如果没有收到另一个通信实体确认信息则会再次重复刚才发送的消息。
这是因为它为当一台计算机需要与另一台远程计算机连接时TCP协议会采用“三次握手”方式让它们建立一个连接用于发送和接收数据的虚拟链路。数据传输完毕TCP协议会采用“四次挥手”方式断开连接。
TCP协议中在发送数据的准备阶段客户端与服务器之间的三次交互以保证连接的可靠。完成三次握手连接建立后客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性TCP协议可以保证传输数据的安全所以应用十分广泛例如下载文件、浏览网页等。 第一次握手客户端向服务器端发出连接请求等待服务器确认。 第二次握手服务器端向客户端回送一个响应通知客户端收到了连接请求。 第三次握手客户端再次向服务器端发送确认信息确认连接。 TCP协议中在发送数据结束后释放连接时需要经过四次挥手。
第一次挥手客户端向服务器端提出结束连接让服务器做最后的准备工作。此时客户端处于半关闭状态即表示不再向服务器发送数据了但是还可以接受数据。第二次挥手服务器接收到客户端释放连接的请求后会将最后的数据发给客户端。并告知上层的应用进程不再接收数据。第三次挥手服务器发送完数据后会给客户端发送一个释放连接的报文。那么客户端接收后就知道可以正式释放连接了。第四次挥手客户端接收到服务器最后的释放连接报文后要回复一个彻底断开的报文。这样服务器收到后才会彻底释放连接。这里客户端发送完最后的报文后会等待2MSL因为有可能服务器没有收到最后的报文那么服务器迟迟没收到就会再次给客户端发送释放连接的报文此时客户端在等待时间范围内接收到会重新发送最后的报文并重新计时。如果等待2MSL后没有收到那么彻底断开。 2.4 Socket编程
通信的协议还是比较复杂的java.net 包中包含的类和接口它们提供低层次的通信细节。我们可以直接使用这些类和接口来专注于网络程序开发而不用考虑通信的细节。
java.net 包中提供了两种常见的网络协议的支持
UDP用户数据报协议(User Datagram Protocol)。TCP传输控制协议 (Transmission Control Protocol)。
通信的两端都要有Socket也可以叫“套接字”是两台机器间通信的端点。网络通信其实就是Socket间的通信。 传输层协议分类类型描述TCP流套接字使用TCP提供可依赖的字节流服务ServerSocket此类实现TCP服务器套接字。服务器套接字等待请求通过网络传入。Socket此类实现客户端套接字也可以就叫“套接字”。套接字是两台机器间通信的端点。UDP数据报套接字使用UDP提供“尽力而为”的数据报服务DatagramSocket此类表示用来发送和接收UDP数据报包的套接字。
3 UDP网络编程
3.1 DatagramSocket和DatagramPacket
1、DatagramSocket
此类表示用来发送和接收数据报包的套接字。数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由也可能按不同的顺序到达。
序号构造器或方法描述1public DatagramSocket(int port)创建数据报套接字并将其绑定到本地主机上的指定端口。套接字将被绑定到通配符地址IP 地址由内核来选择。2public void send(DatagramPacket p)从此套接字发送数据报包。DatagramPacket 包含的信息指示将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。3public void receive(DatagramPacket p)从此套接字接收数据报包。当此方法返回时DatagramPacket 的缓冲区填充了接收的数据。数据报包也包含发送方的 IP 地址和发送方机器上的端口号。 此方法在接收到数据报前一直阻塞。数据报包对象的 length 字段包含所接收信息的长度。如果信息比包的长度长该信息将被截短。4public void close()关闭此数据报套接字。
2、DatagramPacket类
DatagramPacket此类表示数据报包。 数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。
序号构造器和方法描述1public DatagramPacket(byte[] buf,int length)构造 DatagramPacket用来接收长度为 length 的数据包。 length 参数必须小于等于 buf.length。2public DatagramPacket(byte[] buf,int length,InetAddress address,int port)构造数据报包用来将长度为 length 的包发送到指定主机上的指定端口号。length 参数必须小于等于 buf.length。3public int getLength()返回将要发送或接收到的数据的长度。4public byte[] getData()返回数据缓冲区。
3.2 开发步骤
发送端程序包含以下四个基本的 步骤
创建DatagramSocket 默认使用系统随机分配端口号。创建DatagramPacket将要发送的数据用字节数组表示并指定要发送的数据长度接收方的IP地址和端口号。调用 该DatagramSocket 类对象的 send方法 发送数据报DatagramPacket对象。关闭DatagramSocket 对象发送端程序结束关闭通信套接字。
接收端程序包含以下四个基本的步骤
创建DatagramSocket 指定监听的端口号。创建DatagramPacket指定接收数据用的字节数组起到临时数据缓冲区的效果并指定最大可以接收的数据长度。调用 该DatagramSocket 类对象的receive方法 接收数据报DatagramPacket对象。。关闭DatagramSocket 接收端程序结束关闭通信套接字。
3.3 通信模型 3.4 演示发送和接收消息
1、发送端示例代码
package com.atguigu.udp;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;public class Send {public static void main(String[] args)throws Exception {
// 1、建立发送端的DatagramSocketDatagramSocket ds new DatagramSocket();//要发送的数据ArrayListString all new ArrayListString();all.add(尚硅谷让天下没有难学的技术);all.add(学高端前沿的IT技术来尚硅谷);all.add(尚硅谷让你的梦想变得更具体);all.add(尚硅谷让你的努力更有价值);//接收方的IP地址InetAddress ip InetAddress.getByName(127.0.0.1);//接收方的监听端口号int port 9999;//发送多个数据报for (int i 0; i all.size(); i) {
// 2、建立数据包DatagramPacketbyte[] data all.get(i).getBytes();DatagramPacket dp new DatagramPacket(data, 0, data.length, ip, port);
// 3、调用Socket的发送方法ds.send(dp);}// 4、关闭Socketds.close();}
}2、接收端示例代码
package com.atguigu.udp;import java.net.DatagramPacket;
import java.net.DatagramSocket;public class Receive {public static void main(String[] args) throws Exception {
// 1、建立接收端的DatagramSocket需要指定本端的监听端口号DatagramSocket ds new DatagramSocket(9999);//一直监听数据while(true){//2、建立数据包DatagramPacketbyte[] buffer new byte[1024*64];DatagramPacket dp new DatagramPacket(buffer , buffer.length);//3、调用Socket的接收方法ds.receive(dp);//4、拆封数据String str new String(dp.getData(),0,dp.getLength());System.out.println(str);}// ds.close();}
}4 TCP网络编程
4.1 ServerSocket和Socket
1、ServerSocket类
序号构造器或方法描述1ServerSocket(int port)创建绑定到特定端口的服务器套接字。2Socket accept()侦听并接受到此套接字的连接。3public void close()关闭此套接字。
2、Sokcet类
序号构造器或方法描述1public Socket(InetAddress address,int port)创建一个流套接字并将其连接到指定 IP 地址的指定端口号。2public Socket(String host,int port)创建一个流套接字并将其连接到指定主机上的指定端口号。3public InputStream getInputStream()返回此套接字的输入流可以用于接收消息4public OutputStream getOutputStream()返回此套接字的输出流可以用于发送消息5public InetAddress getInetAddress()此套接字连接到的远程 IP 地址如果套接字是未连接的则返回 null。6public int getPort()此套接字连接到的远程端口号如果尚未连接套接字则返回 0。7public InetAddress getLocalAddress()获取套接字绑定的本地地址。8public int getLocalPort()返回此套接字绑定到的本地端口。如果尚未绑定套接字则返回 -1。9public void close()关闭此套接字。套接字被关闭后便不可在以后的网络连接中使用即无法重新连接或重新绑定。需要创建新的套接字对象。 关闭此套接字也将会关闭该套接字的 InputStream 和 OutputStream。10public void shutdownInput()如果在套接字上调用 shutdownInput() 后从套接字输入流读取内容则流将返回 EOF文件结束符。 即不能在从此套接字的输入流中接收任何数据。11public void shutdownOutput()禁用此套接字的输出流。对于 TCP 套接字任何以前写入的数据都将被发送并且后跟 TCP 的正常连接终止序列。 如果在套接字上调用 shutdownOutput() 后写入套接字输出流则该流将抛出 IOException。 即不能通过此套接字的输出流发送任何数据。
**注意**先后调用Socket的shutdownInput()和shutdownOutput()方法仅仅关闭了输入流和输出流并不等于调用Socket的close()方法。在通信结束后仍然要调用Scoket的close()方法因为只有该方法才会释放Socket占用的资源比如占用的本地端口号等。
4.2 开发步骤
服务器端程序包含以下四个基本的 步骤
调用 ServerSocket(int port) 创建一个服务器端套接字并绑定到指定端口上。用于监听客户端的请求。调用 accept() 监听连接请求如果客户端请求连接则接受连接返回通信套接字对象。调用 该Socket 类对象的 getOutputStream() 和 getInputStream () 获取输出流和输入流开始网络数据的发送和接收。关闭Socket 对象客户端访问结束关闭通信套接字。
客户端程序包含以下四个基本的步骤
创建 Socket 根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应则建立客户端到服务器的通信线路。若连接失败会出现异常。打开连接到 Socket 的输入/ 出流 使用 getInputStream()方法获得输入流使用getOutputStream()方法获得输出流进行数据传输按照一定的协议对 Socket 进行读/ 写操作通过输入流读取服务器放入线路的信息但不能读取自己放入线路的信息通过输出流将信息写入线路。关闭 Socket 断开客户端到服务器的连接释放线路
4.3 通信模型
Java语言的基于套接字TCP编程分为服务端编程和客户端编程其通信模型如图所示 4.4 演示单个客户端与服务器单次通信
需求客户端连接服务器连接成功后给服务发送“lalala”服务器收到消息后给客户端返回“欢迎登录”客户端接收消息后断开连接
1、服务器端示例代码
package com.atguigu.tcp.one;import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args)throws Exception {//1、准备一个ServerSocket对象并绑定8888端口ServerSocket server new ServerSocket(8888);System.out.println(等待连接....);//2、在8888端口监听客户端的连接该方法是个阻塞的方法如果没有客户端连接将一直等待Socket socket server.accept();InetAddress inetAddress socket.getInetAddress();System.out.println(inetAddress.getHostAddress() 客户端连接成功);//3、获取输入流用来接收该客户端发送给服务器的数据InputStream input socket.getInputStream();//接收数据byte[] data new byte[1024];StringBuilder s new StringBuilder();int len;while ((len input.read(data)) ! -1) {s.append(new String(data, 0, len));}System.out.println(inetAddress.getHostAddress() 客户端发送的消息是 s);//4、获取输出流用来发送数据给该客户端OutputStream out socket.getOutputStream();//发送数据out.write(欢迎登录.getBytes());out.flush();//5、关闭socket不再与该客户端通信//socket关闭意味着InputStream和OutputStream也关闭了socket.close();//6、如果不再接收任何客户端通信可以关闭ServerSocketserver.close();}
}
2、客户端示例代码
package com.atguigu.tcp.one;import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class Client {public static void main(String[] args) throws Exception {// 1、准备Socket连接服务器需要指定服务器的IP地址和端口号Socket socket new Socket(127.0.0.1, 8888);// 2、获取输出流用来发送数据给服务器OutputStream out socket.getOutputStream();// 发送数据out.write(lalala.getBytes());//会在流末尾写入一个“流的末尾”标记对方才能读到-1否则对方的读取方法会一致阻塞socket.shutdownOutput();//3、获取输入流用来接收服务器发送给该客户端的数据InputStream input socket.getInputStream();// 接收数据byte[] data new byte[1024];StringBuilder s new StringBuilder();int len;while ((len input.read(data)) ! -1) {s.append(new String(data, 0, len));}System.out.println(服务器返回的消息是 s);//4、关闭socket不再与服务器通信即断开与服务器的连接//socket关闭意味着InputStream和OutputStream也关闭了socket.close();}
}
4.5 演示多个客户端与服务器之间的多次通信
通常情况下服务器不应该只接受一个客户端请求而应该不断地接受来自客户端的所有请求所以Java程序通常会通过循环不断地调用ServerSocket的accept()方法。
如果服务器端要“同时”处理多个客户端的请求因此服务器端需要为每一个客户端单独分配一个线程来处理否则无法实现“同时”。
咱们之前学习IO流的时候提到过装饰者设计模式该设计使得不管底层IO流是怎样的节点流文件流也好网络Socket产生的流也好程序都可以将其包装成处理流甚至可以多层包装从而提供更多方便的处理。
案例需求多个客户端连接服务器并进行多次通信
每一个客户端连接成功后从键盘输入英文单词或中国成语并发送给服务器服务器收到客户端的消息后把词语“反转”后返回给客户端客户端接收服务器返回的“词语”打印显示当客户端输入“stop”时断开与服务器的连接多个客户端可以同时给服务器发送“词语”服务器可以“同时”处理多个客户端的请求 1、服务器端示例代码
package com.atguigu.tcp.many;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {// 1、准备一个ServerSocketServerSocket server new ServerSocket(8888);System.out.println(等待连接...);int count 0;while(true){// 2、监听一个客户端的连接Socket socket server.accept();System.out.println(第 count 个客户端socket.getInetAddress().getHostAddress()连接成功);ClientHandlerThread ct new ClientHandlerThread(socket);ct.start();}//这里没有关闭server永远监听}static class ClientHandlerThread extends Thread{private Socket socket;private String ip;public ClientHandlerThread(Socket socket) {super();this.socket socket;ip socket.getInetAddress().getHostAddress();}public void run(){try{//1获取输入流用来接收该客户端发送给服务器的数据BufferedReader br new BufferedReader(new InputStreamReader(socket.getInputStream()));//2获取输出流用来发送数据给该客户端PrintStream ps new PrintStream(socket.getOutputStream());String str;// 3接收数据while ((str br.readLine()) ! null) {//4反转StringBuilder word new StringBuilder(str);word.reverse();//5返回给客户端ps.println(word);}System.out.println(客户端 ip正常退出);}catch(Exception e){System.out.println(客户端 ip意外退出);}finally{try {//6断开连接socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
2、客户端示例代码
package com.atguigu.tcp.many;import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws Exception {// 1、准备Socket连接服务器需要指定服务器的IP地址和端口号Socket socket new Socket(127.0.0.1, 8888);// 2、获取输出流用来发送数据给服务器OutputStream out socket.getOutputStream();PrintStream ps new PrintStream(out);// 3、获取输入流用来接收服务器发送给该客户端的数据InputStream input socket.getInputStream();BufferedReader br;if(args! null args.length0) {String encoding args[0];br new BufferedReader(new InputStreamReader(input,encoding));}else{br new BufferedReader(new InputStreamReader(input));}Scanner scanner new Scanner(System.in);while(true){System.out.println(输入发送给服务器的单词或成语);String message scanner.nextLine();if(message.equals(stop)){socket.shutdownOutput();break;}// 4、 发送数据ps.println(message);// 接收数据String feedback br.readLine();System.out.println(从服务器收到的反馈是 feedback);}//5、关闭socket断开与服务器的连接scanner.close();socket.close();}
}