Java网络编程

网络编程

Java是 Internet上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。 Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控。并且 Java实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境 。

1.1软件架构

C/S架构:全称为Client/Server结构,是指客户端和服务器结构,常见的有qq,美团等

B/S:全称为Browser/Server结构,是指浏览器和服务器结构,通常为浏览器结构.

两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机的通信的程序。

1.2 网络基础

计算机网络: 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件软件、数据信息等资源。 网络编程的目的:直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯。 网络编程中有三个主县的问题: 。问题1:如何准确地定位网络上一台或多台主机 。问题2:如何定位主机上的特定的应用 。问题3:找到主机后,如何可靠、高效地进行数据传输

计算机网络的主要功能

资源共享:资源共享包括计算机硬件资源、软件资源和数据资源的共享。硬件资源的共享提高了计算机硬件资源的利用率,由于受经济和其他因素的制约,这些硬件资派不可能所有用户都有,所以使用计算机网络不仅可以使用自身的硬件资源,也可共享网络上的资源。软件资源和数据资源的共享可以充分利用已有的信息资派.减少软件开发过程中的劳动,避免大型数据库的重复建设。 ​ 信息交换:这是计算机网络最基本的功能.计算机网络中的计算机之间或计算机与终端之间,可以快速可靠地相互传递数据、程序或文件。例如,用户可以在网上传送电子邮件、交换数据,可以实现在商业部门或公司之间进行订单、发票等商业文件安全准确地交换。 ​ 均衡负荷与分布处理:对于大型的任务或课题.如果都集中在一台计算机上.负荷太重,这时可以将任务分散到不同的计算机分别完成,或由网络中比较空闲的计算机分担负荷,各个计算机连成网络有利于共同协作进行重大科研课题的开发和研究。利用网络技术还可以将许多小型机或傲型机连成具有高性能的分布式计算机系统,使它具有解决复杂问题的能力,从而大大降低费用。 综合信息服务: 计算机网络可以向全社会提供各处经济信息、科研情报、商业信息和咨询服务,如Internet中的www就是如此。

计算机网络分类

计算机网络按其覆盖的地理范围可分为如下3类:

局域网(LAN)。局域网是一种在小区域内使用的,由多台计算机组成的网络,覆盖范围通常局限在10 千米范围之内,属于一个单位或部门组建的小范围网。 城域网(MAN)。城域网是作用范围在广域网与局域网之间的网络,其网络覆盖范围通常可以延伸到整个城市,借助通信光纤将多个局域网联通公用城市网络形成大型网络,使得不仅局域网内的资源可以共享,局域网之间的资源也可以共享。 广域网(WAN) 广城网是一种远程网,涉及长距离的通信,覆盖范围可以是个国家或多个国家,甚至整个世界。由于广域网地理上的距离可以超过几千千米,所以信息衰减非常严重,这种网络一般要租用专线,通过接口信息处理协议和线路连接起来,构成网状结构,解决寻径问题。

实现网络通信的三要素

1.使用IP地址

2.端口号

3.网络通信协议

通信要素1:IP地址
1.IP地址的作用

IP地址:指互联网协议地址(InternetProtocolAfdress)俗称IP。IP地址用来给网络中的一台计算机设备做唯一的编号。假如我们把“个人电脑"比作“台电话”的话,那么“IP地址”就相当于“电话号码”。

2.IP地址的分类

IP地址分类方式1:

IPv4: 是一个三十二位的二进制数,通常分为四个字节

类A地址 范围: 从 1.0.0.0 到 126.255.255.255 网络部分: 第一个字节(8位) 主机部分: 后三个字节(24位) 默认子网掩码: 255.0.0.0 或 /8 特点: 类A地址用于大型网络,因为它们提供了大量的主机地址(约1677万个可用地址) 类B地址 范围: 从 128.0.0.0 到 191.255.255.255 网络部分: 前两个字节(16位) 主机部分: 后两个字节(16位) 默认子网掩码: 255.255.0.0 或 /16 特点: 类B地址用于中等规模的网络,提供了较多的主机地址(约65534个可用地址) 类C地址 范围: 从 192.0.0.0 到 223.255.255.255 网络部分: 前三个字节(24位) 主机部分: 最后一个字节(8位) 默认子网掩码: 255.255.255.0 或 /24 特点: 类C地址用于小型网络,提供了较少的主机地址(254个可用地址) 类D地址(多播地址) 范围: 从 224.0.0.0 到 239.255.255.255 特点: 类D地址用于多播通信,允许数据包被发送到多个目的地。 类E地址(实验性地址) 范围: 从 240.0.0.0 到 255.255.255.255 特点: 类E地址保留用于实验和未来使用,不应用于常规网络。 注意事项 127.0.0.0/8地址范围被保留用于环回地址(localhost),即127.0.0.1。 0.0.0.0通常用于表示“无指定地址”,而255.255.255.255是受限广播地址。 由于早期的分类方法导致地址空间的浪费,现代网络设计中通常使用子网划分(Subnetting)和无类别域间路由(CIDR)来更有效地分配IP地址。

IPv6(Internet Protocol version 6)是为了解决IPv4地址耗尽问题而设计的下一代互联网协议。IPv6提供了比IPv4更丰富的地址空间、更高效的路由以及更好的支持移动性和安全性。以下是IPv6的一些关键特点和组成部分:

关键特点: 1.更大的地址空间: IPv6使用128位地址,提供了约3.4 x 10^38个可能的地址,这比IPv4的43亿个地址要多得多。 地址通常表示为8组4个十六进制数,每组之间用冒号(:)分隔,例如:2001:0db8:85a3:0000:0000:8a2e:0370:7334。 2.简化的报头格式: IPv6的报头格式比IPv4更简化,固定长度为40字节,而IPv4报头长度可变。 IPv6移除了许多IPv4报头中的选项,使得路由器处理数据包的速度更快。 3.自动配置: IPv6支持无状态地址自动配置(SLAAC),允许设备在没有DHCP服务器的情况下自动配置自己的地址。 4.内置的IPsec支持: IPv6设计时考虑了安全性,它原生支持IPsec,这是一种用于保护IP通信的协议。 5.改进的多播和任播支持: IPv6对多播(一个源发送数据包到多个目的地)和任播(数据包发送到一组接口中的任意一个)提供了更好的支持。 地址类型 单播地址:用于标识单一网络接口。 多播地址:用于标识一组接口,数据包发送到多播地址会被该组内所有接口接收。 任播地址:用于标识一组接口,数据包发送到任播地址时,只会被该组中的一个接口接收(通常是最近的一个)

IP地址分类方式2

公网地址和私网地址

  1. 类A私有地址范围:

    • 网络地址: 10.0.0.0

    • 广播地址: 10.255.255.255

    • 可用的主机地址范围: 10.0.0.110.255.255.254

    • 子网掩码: 255.0.0.0/8

  2. 类B私有地址范围:

    • 网络地址: 172.16.0.0

    • 广播地址: 172.31.255.255

    • 可用的主机地址范围: 172.16.0.1172.31.255.254

    • 子网掩码: 255.255.0.0/16

    • 这个范围进一步细分为16个子网,每个子网拥有65534个可用的主机地址。

  3. 类C私有地址范围:

    • 网络地址: 192.168.0.0

    • 广播地址: 192.168.255.255

    • 可用的主机地址范围: 192.168.0.1192.168.255.254

本地回路地址

127.0.0.1

域名

域名(Domain Name)是互联网上用于识别和定位计算机的一种层次结构的名称。它为复杂的IP地址提供了一种易于记忆和识别的替代方式。域名系统(DNS)将域名转换为与之对应的IP地址,使得用户可以通过易于记忆的域名访问互联网上的资源。

域名结构

域名由多个部分组成,通常从右到左读取,每个部分称为一个标签,标签之间用点(.)分隔。例如,在域名 www.example.com 中:

  • com 是顶级域名(TLD),表示域名的类型或注册机构。

  • example 是二级域名,通常由注册域名的个人或组织拥有。

  • www 是三级域名(有时称为主机名或子域名),用于指向特定的服务器或服务。

顶级域名(TLD)

顶级域名分为几个类别:

  1. 1.通用顶级域名(gTLD):如 .com.org.net.info 等。

  2. 2.国家代码顶级域名(ccTLD):如 .us(美国)、.uk(英国)、.cn(中国)等,每个国家或地区都有自己的ccTLD。

  3. 3.新通用顶级域名(new gTLD):近年来,互联网名称与数字地址分配机构(ICANN)批准了许多新的gTLD,如 .app.blog.shop 等。

域名注册

域名注册是购买域名使用权的过程。注册域名通常需要通过域名注册商进行,这些注册商是经过认证的机构,负责处理域名的注册、续费和管理。注册域名时,你需要确保域名是唯一的,没有被其他人或组织注册。

域名解析

域名解析是将域名转换为IP地址的过程。当你在浏览器中输入一个域名时,你的计算机通过DNS查询来解析这个域名,找到对应的IP地址,然后连接到正确的服务器。

域名的其他用途

除了用于网站访问外,域名还可以用于电子邮件(如 [email protected])、FTP服务器和其他网络服务。

注意事项

  • 域名的注册通常有一定的有效期,到期后需要续费以保持域名的使用权。

  • 选择域名时,应考虑其品牌价值、易记性以及与业务的相关性。

  • 保护个人隐私:一些注册商提供隐私保护服务,可以隐藏注册人的联系信息,防止滥用。

端口号

不同的进程有不同的端口号

端口号(Port Number)是用于标识网络中特定进程或服务的数字。在互联网协议(IP)地址的基础上,端口号允许一台计算机上的多个应用程序同时使用网络连接,而不会相互干扰。端口号是传输层协议(如TCP或UDP)的一部分,用于区分不同应用程序之间的数据流。

端口号范围

端口号的范围是从0到65535。端口号分为以下三个主要范围:

  1. 1.

    知名端口(Well-Known Ports):范围从0到1023,这些端口号被预留给一些特定的服务和应用程序。例如:

    • HTTP服务通常使用端口80。

    • HTTPS服务通常使用端口443。

    • FTP服务通常使用端口21。

    • SSH服务通常使用端口22。

    • Telnet服务通常使用端口23。

  2. 2.注册端口(Registered Ports):范围从1024到49151,这些端口号被分配给特定的应用程序或服务。这些端口通常由互联网号码分配机构(IANA)进行管理,但不像知名端口那样严格控制。

  3. 3.动态或私有端口(Dynamic or Private Ports):范围从49152到65535,这些端口号用于临时分配给客户端应用程序。当客户端应用程序需要与服务器通信时,操作系统会从这个范围内选择一个未使用的端口号。

端口号的作用

端口号使得网络通信可以是多路复用的,即多个应用程序可以同时使用同一个IP地址进行通信。例如,一个Web服务器可能同时运行多个服务(如HTTP、HTTPS、FTP),每个服务使用不同的端口号来区分不同的请求。

端口与协议

端口号与传输层协议(如TCP或UDP)一起使用。不同的协议可以使用相同的端口号,但它们是独立的。例如,HTTP服务通常使用TCP端口80,而HTTPS服务使用TCP端口443。

安全性考虑

端口号的选择对于网络安全非常重要。开放不必要的端口可能会增加安全风险,因为攻击者可能会尝试通过这些端口访问系统。因此,通常建议关闭或限制对非必要服务端口的访问。

端口号是网络通信中不可或缺的一部分,它们使得网络服务能够高效、有序

网络通信协议

网络通信协议是计算机网络中用于实现不同设备之间数据交换的一套规则和标准。这些协议定义了数据如何在网络中传输、如何被接收方正确解析以及如何处理错误和重传等问题。网络通信协议通常分为几个层次,每个层次负责不同的通信功能。最著名的网络通信协议模型是OSI(开放系统互连)模型和TCP/IP模型。

OSI模型

OSI(开放系统互连)模型是一个理论上的七层模型,用于标准化网络通信过程。每一层都有特定的功能和协议:

  1. 1.物理层(Layer 1):负责传输原始比特流(0和1)通过物理介质。

  2. 2.数据链路层(Layer 2):负责在相邻节点之间建立、维护和终止链路,处理错误检测和纠正。

  3. 3.网络层(Layer 3):负责数据包从源到目的地的传输和路由选择。

  4. 4.传输层(Layer 4):负责提供端到端的数据传输服务和错误检查。

  5. 5.会话层(Layer 5):负责建立、管理和终止会话。

  6. 6.表示层(Layer 6):负责数据的表示、安全、压缩。

  7. 7.应用层(Layer 7):负责为应用软件提供网络服务。

TCP/IP模型

TCP/IP模型是一个实际应用的四层模型,它与OSI模型类似,但更为简洁:

  1. 1.网络接口层:对应于OSI模型的物理层和数据链路层。

  2. 2.网络层:对应于OSI模型的网络层,使用IP协议(Internet Protocol)。

  3. 3.传输层:对应于OSI模型的传输层,使用TCP(Transmission Control Protocol)或UDP(User Datagram Protocol)。

  4. 4.应用层:对应于OSI模型的会话层、表示层和应用层,包含多种协议,如HTTP、FTP、SMTP等。

层次 OSI参考模型功能 TCP/IP参考模型功能 TCP/IP参考模型协议
应用层 为应用程序提供服务 应用程序 HTTP、FTP、Telnet、DNS
表示层 数据格式转化、数据加密 - -
会话层 建立、管理和维护会话 - -
传输层 建立、管理和维护端对端的连接 TCP、UDP TCP、UDP
网络层 IP选址及路由选择 IP、ICMP、ARP IP、ICMP、ARP
数据链路层 提供介质访问和链路管理 Link -
物理层 物理传输 设备驱动程序、网络接口 -

常见的网络通信协议

  • IP(Internet Protocol):定义了数据包的格式和寻址方式,是网络层的核心协议。

  • TCP(Transmission Control Protocol):提供可靠的、面向连接的传输服务,保证数据正确无误地送达。

  • UDP(User Datagram Protocol):提供无连接的传输服务,适用于对实时性要求高的应用,如视频流或在线游戏。

  • HTTP(Hypertext Transfer Protocol):用于从Web服务器传输超文本到本地浏览器的协议。

  • HTTPS(HTTP Secure):HTTP的安全版本,通过SSL/TLS提供加密和身份验证。

  • FTP(File Transfer Protocol):用于在网络上进行文件传输的协议。

  • SMTP(Simple Mail Transfer Protocol):用于发送电子邮件的协议。

  • DNS(Domain Name System):将域名转换为IP地址的系统。

InetAddress(网络地址)

InetAddress类的对象代表一个IP地址

创建对象的方式:

InetAddress getByName(String host)

InetAddress getLocalHost()

 public class InetAddressTest {
     public static void main(String[] args) {
 ​
 //        实例化 getByName(String host)
         try {
             InetAddress byName = InetAddress.getByName("192.168.23.31");
             System.out.println(byName);
 ​
             InetAddress byName2 = InetAddress.getByName("www.jd.com");
             System.out.println(byName2);
 ​
 ​
 //            getlocalhost
 ​
             InetAddress byName3 = InetAddress.getLoopbackAddress();
             System.out.println(byName3);
         } catch (UnknownHostException e) {
           e.printStackTrace();
         }
 ​
 ​
 ​

常用方法:

InetAddress 是 Java 中用于表示 IP 地址的类。它提供了多种方法来处理 IP 地址。以下是一些常用的 InetAddress 类的方法:

  • 1.getByName(String host):根据提供的主机名(可以是域名或IP地址的字符串形式)返回对应的 InetAddress 实例。

  • 2.getLocalHost():返回表示本地主机的 InetAddress 实例。

  • 3.getHostAddress():返回 IP 地址的字符串形式(例如,"192.168.1.1")。

  • 4.getHostName():返回此 IP 地址的主机名。如果无法解析主机名,则返回 IP 地址的文本表示形式。

  • 5.isReachable(int timeout):测试是否可以达到该地址的主机。timeout 参数指定等待响应的最大毫秒数。

  • 6.isMulticastAddress():对于 IPv4 地址,如果地址是多播地址,则返回 true;对于 IPv6 地址,此方法总是返回 false

  • 7.isAnyLocalAddress(), isLinkLocalAddress(), isSiteLocalAddress():这些方法用于判断 IP 地址是否属于特定的本地地址范围。

  • 8.getAddress():返回 IP 地址的字节数组形式。

这些方法使得 InetAddress 类非常方便用于网络编程中处理 IP 地址。需要注意的是,InetAddress 类没有公开的构造函数,因此不能直接实例化,必须使用上述静态方法来获取 InetAddress 实例。

下面是一个简单的例子,演示如何使用 InetAddress 类的一些方法:

 import java.net.InetAddress;
 import java.net.UnknownHostException;
 ​
 public class InetAddressExample {
     public static void main(String[] args) {
         try {
             // 获取本地主机的 InetAddress 实例
             InetAddress localHost = InetAddress.getLocalHost();
             System.out.println("Local host name: " + localHost.getHostName());
             System.out.println("Local host address: " + localHost.getHostAddress());
 ​
             // 获取并打印一个特定主机的 InetAddress 实例
             InetAddress google = InetAddress.getByName("www.google.com");
             System.out.println("Google host name: " + google.getHostName());
             System.out.println("Google host address: " + google.getHostAddress());
             
             // 测试是否可以达到该地址的主机
             if (google.isReachable(1000)) {
                 System.out.println("Google is reachable.");
             } else {
                 System.out.println("Google is not reachable.");
             }
         } catch (UnknownHostException e) {
             e.printStackTrace();
         }
     }
 }

TCP/UDP协议

TCP(传输控制协议)和 UDP(用户数据报协议)是互联网协议套件(TCP/IP)中用于数据传输的两种主要传输层协议。它们各自有不同的特点和用途:

TCP(传输控制协议)

  1. 1.面向连接:在数据传输之前,TCP 需要建立一个连接,这通常通过三次握手过程完成。

  2. 2.可靠传输:TCP 提供可靠的数据传输服务。它通过序列号、确认应答、流量控制和拥塞控制机制确保数据正确无误地到达目的地。

  3. 3.有序传输:TCP 保证数据包的顺序,即使它们到达的顺序可能被打乱,接收方也会重新排序这些数据包。

  4. 4.面向字节流:TCP 不保留记录边界,这意味着数据被视为无结构的字节流。

  5. 5.全双工通信:TCP 允许数据在两个方向上同时进行传输。

  6. 6.使用场景:适用于对数据完整性和顺序有严格要求的应用,如网页浏览(HTTP/HTTPS)、文件传输(FTP)、电子邮件(SMTP)等。

常用术语:

Seq (Sequence number)顺序号码

SYN(synchronous)表示建立连接,

FIN(finish结束)表示关闭连接,

ACK(acknowledgement 确认)表示响应,

PSH(push)表示有 DATA数据传输,

RST(reset)表示连接重置。

1、TCP报文格式

上图中有几个字段需要重点介绍下: (1)序号:Seq()序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。 (2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。 (3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下: (A)URG:紧急指针(urgent pointer)有效。 (B)ACK:确认序号有效。 (C)PSH:接收方应该尽快将这个报文交给应用层。 (D)RST:重置连接。 (E)SYN:发起一个新连接

1、客户端会随机一个初始序列号seq=x,设置SYN=1,表示这是SYN握手报文。然后就可以把这个 SYN 报文发送给服务端了,表示向服务端发起连接,之后客户端处于 同步已发送 状态。 2、服务端收到客户端的 SYN 报文后,也随机一个初始序列号(seq=y),设置ack=x+1,表示收到了客户端的x之前的数据,希望客户端下次发送的数据从x+1开始。设置 SYN=1 和 ACK=1。表示这是一个SYN握手和ACK确认应答报文。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 同步已接收 状态。 3、客户端收到服务端报文后,还要向服务端回应最后一个应答报文,将ACK置为1,表示这是一个应答报文ack=y+1 ,表示收到了服务器的y之前的数据,希望服务器下次发送的数据从y+1开始。最后把报文发送给服务端,这次报文可以携带数据,之后客户端处于 连接已建立 状态。服务器收到客户端的应答报文后,也进入 连护己建立 状态

1、客户端打算断开连接,向服务器发送FIN报文(FIN标记位被设置为1,1表示为FIN,0表示不是),FI报文牛会指定一个序列号,之后客户端进入FIN_WAIT_1状态。也就是客户端发出连接释放报文段(FIN报文),指定序列号seq=u,主动关闭TCP连接,等待服务器的确认。 2、服务器收到连接释放报文段(FIN报文)后,就向客户端发送ACK应答报文,以客户端的FIN报文的序列号seq+1 作为ACK应答报文段的确认序列号ack=seq+1=u+1。接着服务器进入CLOSE_WAIT(等待关闭)状态,此时的TCP处于半关闭状态(下面会说什么是半关闭状态),客户端到服务器的连接释放。客户端收到来自服务器的ACK应签报文段后,进入FINWAIT_2状态。 3、服务器也打算断开连接,向客户端发送连接释放(FIN)报文段,之后服务器进入LASK_ACK(最后确认)状态等待客户端的确认。服务器的连接释放(FIN)报文段的FIN=1,ACK=1,序列号seq=m,确认序列号ack=u+1。 4、客户端收到来自服多1连接释放报文段后服务器发送一个ACK应签报文段,以连接释放(FIN)报文段的确认序号 àck 作为ACK应签报文段的序列以连接释放(FIN)报文段的序列号 seq+1作为确认序se0.号ack。 之后客户端进入TIME WAIT(时间等待)状态,服务器收到ACK应答报文段后,服务器就进入CLOSE(关闭)状态到此服务器的连接已经完成关闭。客户端处于TIME_WAIT状态时,此时的TCP还未释放掉,需要等待2MSL后客户端才进入CLOSE状态。

UDP(用户数据报协议)

  1. 1.无连接:UDP 在发送数据之前不需要建立连接,直接发送数据包。

  2. 2.不可靠传输:UDP 不保证数据包的送达,也不保证顺序,不提供重传机制。

  3. 3.无序传输:UDP 不保证数据包的顺序,接收方可能收到乱序的数据包。

  4. 4.面向数据报:UDP 保留了数据报的边界,这意味着每个数据包都是独立的。

  5. 5.低延迟:由于没有建立连接和维护连接的开销,UDP 通常具有较低的延迟。

  6. 6.使用场景:适用于对实时性要求高,可以容忍一定数据丢失的应用,如在线游戏、实时视频会议、流媒体等。

 public class UDPTest {
 @Test
     public void sender() throws Exception {
 //        创建一个对象
         DatagramSocket ds = new DatagramSocket();
         //将目的地的ip,端口封装在DatagramPacket
         InetAddress intAddress = InetAddress.getByName("127.0.0.1");
         int port = 9090;
         byte[] bytes = "fsd".getBytes("UTF-8");
         DatagramPacket dp = new DatagramPacket(bytes,0,bytes.length, intAddress, port);
 //      发送数据
         ds.send(dp);
         ds.close();
 ​
     }
 @Test
     public void receiver() throws Exception {
 ​
         //创建一个对象
         int port = 9090;
         DatagramSocket ds = new DatagramSocket(port);
         //创建数据报对象,
         byte[] buf = new byte[1024 * 64];
         DatagramPacket dp = new DatagramPacket(buf, 0, buf.length);
 //      接收数据
         ds.receive(dp);
         String str= new String(dp.getData(),0,dp.getLength());
          System.out.println(str);
         ds.close();
     }
 }

总结

TCP 提供了一种可靠、有序、面向连接的数据传输服务,适用于需要保证数据完整性和顺序的场景。而 UDP 提供了一种简单、快速、无连接的数据传输服务,适用于对实时性要求高但可以容忍一定数据丢失的场景。根据应用的具体需求选择合适的协议是非常重要的。

Sorket类

网络上具有唯一标识的IP地址和端口号组合在一起构成唯一能识别的标识符套接字(Sorket) 利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实上的标准。网络通信其实就是Socket间的通信。 通信的两端都要有socket,是两台机器间通信的端点。 Socket允许程序把网络连接当成数据在两个socket间通过10传输。-一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。Socket分类: 流套接字(stream socket):使用TCP提供可依赖的字节流服务 "ServerSocket:此类实现TCP服务器套接字。服务器套接字等待请求通过网络传入。。

Socket:此类实现客户端套接字(也可以就叫“套接字”)。

套接字是两台机器间通信的端点。数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务

DatagramSocket:此类表示用来发送和接收UDP数据报包的套接字

 public class TCPTest1 {
     @Test
     public void send() {
         //创建一个socket
         Socket socket = null;
         OutputStream ou = null;
         try {
             InetAddress address = InetAddress.getByName("127.0.0.1");
             int port = 8989;//声明端口号
             socket = new Socket(address,port);
 ​
             //发送数据
             ou = socket.getOutputStream();
             ou.write("client".getBytes());
         } catch (IOException e) {
             throw new RuntimeException(e);
         } finally {
             try{
                 if (socket != null){
                     socket.close();
                 }
             }catch (IOException e){
                 e.printStackTrace();
             }
             try{
                 if (ou != null){
                     ou.close();
                 }
             }catch (IOException e){
                 e.printStackTrace();
             }
         }
 //        关闭socket
 ​
     }
 ​
     @Test
     public void server(){
         //创建一个serverSocket
         ServerSocket serverSocket = null;
         InputStream is= null;
         Socket socket = null;
         try {
             int port = 8989;
             serverSocket = new ServerSocket(port);
             //调用accept() 接收客户端的Scoket
             socket = serverSocket.accept();
             System.out.println("fuwuqi");
 //        接收数据
             is = socket.getInputStream();
             byte[] b = new byte[5];
             int len;
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             while ((len = is.read(b)) != -1) {
                 baos.write(b,0,len);
 //                System.out.println(new String(b, 0, len));
 //                len = is.read(b);
             }
             System.out.println(baos.toString());
 ​
             System.out.println("update");
         } catch (IOException e) {
             e.printStackTrace();
         } finally {
             try{
                 if (serverSocket != null) {
                     serverSocket.close();
                 }
             }catch (IOException e){
                 e.printStackTrace();
             }
             try{
                 if (socket != null) {
                     socket.close();
                 }
             }catch (IOException e){
                 e.printStackTrace();
             }
             try{
                 if (is != null) {
                     is.close();
                 }
             }catch (IOException e){
                 e.printStackTrace();
             }
         }
 //        关闭socket
 ​
 ​
      }
 }
 ​

客户端发送文件给服务端,服务端将文件保存在本地

 package inetaddress;
 ​
 import org.junit.jupiter.api.Test;
 ​
 import java.io.*;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
 ​
 ​
 public class TCPTest2 {
     @Test
     public void Server() throws IOException {
         //创建serversocket
         int port = 9090;
         ServerSocket serverSocket = new ServerSocket(port);
 ​
         //接收来自客户端的socket.accept
         Socket socket = serverSocket.accept();
 ​
         //通过socket获取一个socket
         InputStream is = socket.getInputStream();
         //读写过程
         File file = new File("img_copy.png");
         FileOutputStream fos = new FileOutputStream(file);
         byte[] buffer = new byte[1024];
         int len = 0;
         while ((len = is.read(buffer)) != -1) {
             fos.write(buffer, 0, len);
         }
         //关闭流
         fos.close();
         is.close();
         socket.close();
     }
     @Test
     public void Client() throws IOException {
         //创建socket(指明对方的ip和端口)
         InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
         int port = 9090;
         Socket socket = new Socket(inetAddress, port);
         //创建file的实例,FileInputStream的实例
         File file = new File("img.png");
         FileInputStream fis = new FileInputStream(file);
         //通过socket输出
         OutputStream os = socket.getOutputStream();
 ​
         //读写数据
         byte[] buf = new byte[1024];
         int len;
         while((len = fis.read(buf)) != -1){
             os.write(buf,0,len);
         }
         //关闭socket
         os.close();
         fis.close();
         socket.close();
     }
 }

URL编程

统一定位资源符(种子)

(uniform resource locator)

作用:一个具体的url就对应这互联网上某一资源的地址

URL的格式:

http://127.0.0.1:8080/examples/abcd.jpg?name=Tom

应用层协议 IP地址 端口号 资源地址 参数列表

 public class URLTest {
     public static void main(String[] args) {
         String str = "http://127.0.0.1:8080/examples/abcd.jpg?name=Tom";
 ​
         try {
             URL url = new URL(str);
             
             
         } catch (MalformedURLException e) {
             e.printStackTrace();
         }
 ​
     }
 }
 ​

url下载:

 public class URLTest1 {
 ​
         @Test
         public void test1() throws IOException {
             URL url = new URL("http://127.0.0.1:8080/examples/abcd.jpg?name=Tom");
 ​
             HttpURLConnection urlConnection =(HttpURLConnection) url.openConnection();
 ​
             InputStream is = urlConnection.getInputStream();
             File file = new File("des.jpg");
             FileOutputStream fos = new FileOutputStream(file);
             byte[] buf = new byte[1024];
             int len;
             while((len=is.read(buf))!=-1){
                 fos.write(buf, 0, len);
 ​
             }
 ​
             fos.close();
             is.close();
             urlConnection.disconnect();
         }
 ​
 }
 ​

你可能感兴趣的:(java,网络,开发语言)