欢迎来真孝善网,为您提供真孝善正能量书籍故事!

2020新征程:JAVA基础与网络编程学习指南

时间:11-13 神话故事 提交错误

Java网络编程

随着互联网的发展趋势,大量的二网应用涌现,使得网络编程技术得到了良好的发展。网络编程是在两个或多个设备(例如计算机)之间传输数据。程序员所做的就是发送数据到指定的位置或者接收指定的数据。这是狭义上的网络编程。

有些API是用Java语言设计的,专门实现数据发送、接收等功能,只需要程序员调用即可。要进行网络编程,您必须对网络协议、端口和套接字有一定的了解。

Java网络编程基础知识

网络编程的目的是通过网络协议直接或间接地与其他计算机进行通信。 Java 语言包含网络编程所需的各种类。程序员只需创建这些类的对象并调用相应的方法即可编写网络应用程序。

编写网络程序,程序员需要对网络传输协议、端口、套接字等有一定的了解。

网络分类

在了解网络编程之前,我们首先带领读者对计算机网络有一些简单的了解。计算机网络是指多台具有独立功能的计算机通过通信设备线路连接起来,并在网络软件的支持下,实现相互之间的资源共享和数据通信的整个系统。

按照地理范围主要将网络分为局域网、城域网、广域网和因特网。局域网(LAN),简称LAN,是在小区域内实现的计算机网络。它通常在建筑物或工厂或公共机构内是唯一的,并且范围较小。城域网(Metropolitan Area Network),简称城域网(MAN),一般是在城市内部建立的、提供全市信息服务的计算机信息网络。广域网(WAN)简称WAN。它的范围很广,可以分布在一个省、一个国家或几个国家。互联网由无数的LAN 和WAN 组成。

网络编程模型

网络通讯主要有两种通讯方式:一种是客户机/服务器(Client/Server)模式,简称为 C/S 模式另一种是浏览器/服务器(Browser/Server)模式,简称 B/S 模式。下面主要介绍这两种模式。

Client/Server 模式

图是客户端、服务器和网络的关系图。采用这种模式的程序有很多,比如网络游戏,需要在本地机器上安装客户端,服务器运行在游戏开发公司的机房。

C/S模式采用C/S模式程序,需要分别为客户端和服务器专门开发。这种开发模式的优势在于由于客户端是专门开发的,表现力会更强。缺点就是通用性差,也就是说一种程序的客户端只能和对应的服务器端进行通信,不能和其他的服务器端进行通信。在实际维护中,还需要维护特殊的客户端和服务器,这给维护带来了很大的压力。

Browser/Server 模式

对于许多程序,运行时不需要专门的客户端,而是使用通用客户端,例如浏览器。用户使用浏览器作为客户端的这种模式叫作浏览器/服务器模式。使用这种模式开发程序时,只需要开发服务器端即可。开发压力较小,无需维护客户端。但对浏览器的限制比较大,表现力不强。

网络协议

网络协议是网络上所有设备(网络服务器、计算机和交换机、路由器、防火墙等)之间通信规则的集合。它规定了信息在通信过程中必须使用的格式以及这些格式的含义。目前网络协议有很多种。这里我们简单介绍一下几种常用的网络协议。

IP 协议

IP是英文Internet Protocol(网络之间互联的协议)的缩写,中文缩写是Internet Protocol,即为计算机网络相互连接进行通信而设计的协议在 Internet 中它是能使连接到网上的所有计算机网络实现相互通信的一套规则,规定了计算机在 Internet 上进行通信时应当遵守的规则。任何厂家生产的计算机系统只有遵守 IP 协议才可以与 Internet 互联。Internet网络中使用的协议是TCP/IP协议,其全称是传输控制协议/Internet协议。互联网依靠TCP/IP协议在全球范围内互连不同的硬件结构、不同的操作系统、不同的网络。

对于网络编程来说,主要是计算机之间的通信。首要问题是如何找到网络上数以亿计的计算机。为了解决这个问题,网络上的每个设备都会有一个唯一的数字标识,这就是IP地址。

在计算机网络中,现在命名 IP 地址的规定是 IPv4 协议,该协议规定每个 IP 地址由 4 个 0~255 的数字组成。连接到网络的每台计算机都有一个唯一的IP 地址,该地址可以是固定的或动态的。

目前,IETF(互联网工程任务组)设计的下一代协议IPv6 用来取代当前版本的IP 协议(IPv4),使用6 个字节来表示IP 地址,但尚未得到使用。

TCP/IP 定义了电子设备如何连接到互联网以及如何在它们之间传输数据的标准。协议采用 4 层的层级结构,分别是应用层、传输层、网络层和网络接口层。每层调用其下层提供的网络来满足其需求。

TCP负责发现传输问题,一旦出现问题就发出信号请求重传,直到所有数据安全正确地传输到目的地,而IP则为互联网上的每台计算机指定一个地址。图2 是TCP/IP 层次结构图。

TCP/IP 层次结构

TCP 与 UDP 协议

尽管TCP/IP 协议的名称仅包含协议名称TCP、但是在 TCP/IP 协议的传输层同时存在 TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Datagram Protocol,用户数据报协议)两个协议

在网络通信中,TCP协议类似于用手机打电话,可以保证信息传递给别人;而UDP协议类似于发送短信,接收方可能收不到发送的信息。

在网络通信中使用TCP需要建立专用的虚拟连接,然后建立可靠的数据连接。如果数据传输失败,客户端会自动重发数据。使用UDP不需要建立专门的虚连接,传输也不是很可靠。如果传输失败,客户端无法获取。

TCP 协议是一种以固定连线为基础的协议,它提供两台计算机之间可靠的数据传送。而 UDP 无连接通信协议,它不保证可靠数据的传输,但能够向若干目标发送数据以及接收来自若干源的数据。对于一些重要的数据,一般采用TCP进行数据传输,而大量的非核心数据则通过UDP进行传输。使用TCP的传输速度稍慢,并且传输过程中产生的数据量会比UDP更大。

套接字和端口

Internet上的许多应用程序采用客户端/服务器(C/S)模型。要实现网络通信,必须将两台计算机连接起来,建立双向通信链路。此双向通信链路的每一端将其称为套接字。

一台服务器上可能提供多种服务,使用 IP 地址只能唯一定位到某一台计算机,却不能准确地连接到想要连接的服务器。通常使用一个 0~65535 的整数来标识该机器上的某个服务,这个整数就是端口号(Port)。端口号并不指计算机上的实际物理位置,而是一个软件抽象。

端口号主要分为以下两类:

ICANN(互联网名称与数字地址分配机构)分配的众所周知的端口,被一些常用的应用层程序固定使用,其值为0~1023。例如HTTP服务一般使用80端口,FTP服务使用21端口。一般端口用于分配随时请求通信的客户端进程。运行在特定机器上的服务器(例如FTP服务器)有一个绑定到服务器的套接字,服务器只是等待并监听客户端的连接请求。客户端客户端需要知道服务器的主机名和端口号。

为了建立连接请求,客户端尝试连接到服务器上指定端口号上的服务。这个请求流程如图所示。

客户端向服务器发送请求。如果服务器收到客户端的请求,就会创建一个套接字。客户端使用socket与服务器进行通信,但是此时客户端的socket并没有绑定到与服务器连接的端口。就号码而言。

Java InetAddress类及其常用方法

Internet上的主机有两种表示地址的方式,即域名和IP地址。java.net 包中的 InetAddress 类对象包含一个 Internet 主机地址的域名和 IP 地址

InetAddress 类提供了操作 IP 地址的各种方法。该类本身没有构造方法,而是通过调用相关静态方法获取实例。 InetAddress 类中常用的方法如下表所示。

方法名称说明boolean equals(Object obj) 将此对象与指定对象进行比较byte[] getAddress() 返回此InetAddress 对象的原始IP 地址static InetAddress[] getAHByName(String host) 给定主机名,根据系统上的配置的名称,服务器返回一个由其IP 地址组成的数组static InetAddress getByAddress(byte[] addr) 在给定原始IP 地址的情况下返回InetAddress 对象static InetAddress getByAddress(String host) 给定主机名确定主机的IP 地址。 String getCanonicalHostName() 获取此IP 地址的完全限定域名。 String getHostAddress() 返回IP 地址字符串(以文本表示形式)。 String getHostName() 返回此IP 地址的主机名。 static InetAdderss getLocalHost() returns 本地主机示例编写一个程序来练习InetAddress类的基本用法。主要步骤如下。

(1) 创建一个类。在main()方法中创建一个InetAddress对象,调用getByName()方法并传递参数“www.qq.com”,输出该对象的IP地址字符串和主机名代码,如下所示。

公共静态无效主(字符串[]参数)

{

尝试

{

InetAddress ia1=InetAddress.getByName("www.qq.com");

System.out.println(ia1.getHostName());

System.out.println(ia1.getHostAddress());

}

捕获(UnknownHostException e)

{

e.printStackTrace();

}

}(2)在main()方法中添加代码,创建一个InetAddress对象,调用getByName()方法并传入参数“61.135.169.105”,输出该对象的IP地址字符串和主机名,如下所示。

尝试

{

InetAddress ia2=InetAddress.getByName("61.135.169.105");

System.out.println(ia2.getHostName());

System.out.println(ia2.getHostAddress());

}

捕获(UnknownHostException e)

{

e.printStackTrace();

}(3)创建InetAddress对象来获取本地主机信息,并输出该对象的IP地址字符串和主机名,如下所示。

尝试

{

InetAddress ia3=InetAddress.getLocalHost();

System.out.println("主机名:"+ia3.getHostName());

System.out.println("本机ip地址:"+ia3.getHostAddress());

}

捕获(UnknownHostException e)

{

e.printStackTrace();

}(4)执行程序,运行结果如下。

QQ网

123.151.137.18

61.135.169.105

61.135.169.105

主机名:WQ-20161107KCPN

本地IP地址:192.168.0.102 注意:以上代码中包含了互联网地址,因此运行时需要连接互联网,否则会出现异常。

Java TCP通信:Java ServerSocket类和Socket类

TCP网络程序是指使用Socket编写的通信程序。使用TCP协议进行通信的两个应用程序分为主应用程序和次应用程序。一个是服务器程序,另一个是客户端程序。两者的功能和写法不同。其中ServerSocket 类表示 Socket 服务器端,Socket 类表示 Socket 客户端,两者交互过程如下:

服务器创建一个ServerSocket(服务器端套接字)并调用accept()方法等待客户端连接。客户端程序创建一个Socket并向服务器请求连接。服务器收到客户端的连接请求,创建一个新的Socket与客户端建立连接。服务器继续等待新的请求。

ServerSocket 类

ServerSocket 类是与 Socket 类相对应的用于表示通信双方中的服务器端,用于在服务器上开一个端口,被动地等待数据(使用 accept() 方法)并建立连接进行数据交互。服务器套接字一次只能连接到一个套接字。如果多个客户端同时发出连接请求,服务器套接字会将请求连接的客户端存储到队列中,然后从中取出一个套接字。该套接字连接到服务器创建的新套接字。如果请求的连接数大于最大连接数,则拒绝额外的连接请求;默认队列大小为50。

ServerSocket 的构造方法

ServerSocket的构造方法如下。

ServerSocket():无参构造方法。 ServerSocket(int port):创建绑定到特定端口的服务器套接字。 ServerSocket(int port,int backlog):使用指定的backlog创建服务器套接字并将其绑定到指定的本地端口。 ServerSocket(int port,int backlog,InetAddress bindAddr):使用指定端口、监听backlog和要绑定到本地的IP地址创建一个服务器。上述方法的参数中,port指的是本地TCP端口,backlog指的是监听backlog,bindAddr指的是服务器绑定的InetAddress。

创建ServerSocket时可能会抛出IOException,因此需要异常捕获。以下是使用8111端口的ServerSocket示例代码。

尝试{

ServerSocket serverSocket=new ServerSocket(8111);

}catch(IOException e){

e.printStackTrace();

}

ServerSocket 的常用方法

ServerSocket的常用方法如下。

服务器accept():侦听并接收此套接字的连接。 voidbind(SocketAddressendpoint):将ServerSocket绑定到指定地址(IP地址和端口号)。 void close():关闭此套接字。 InetAddress getInetAddress():返回此服务器套接字的本地地址。 int getLocalPort():返回此套接字侦听的端口。 SocketAddress getLocalSoclcetAddress():返回此套接字绑定到的端口的地址,如果尚未绑定,则返回null。 int getReceiveBufferSize():获取此ServerSocket 的SO_RCVBUF 选项的值,这是从ServerSocket 接收套接字的建议缓冲区大小。调用accept()方法将返回一个连接到客户端的Socket对象服务器端的 Socket 对象使用 getOutputStream() 方法获得的输出流将指定客户端 Socket 对象使用 getInputStream() 方法获得那个输入流的Socket对象。同样,服务器端的 Socket 对象使用的 getInputStream() 方法获得的输入流将指向客户端 Socket 对象使用的 getOutputStream() 方法获得的那个输出流。也就是说,当服务器向输出流写入信息时,客户端可以通过相应的输入流读取信息,反之亦然。整个流程如图所示。

了解了上面的基础知识后,使用ServerSocket 类在本机上使用8888 端口创建服务器端套接字。示例代码如下。

公共静态无效主(字符串[]参数)

{

尝试

{

//在端口8888上创建服务器端套接字

ServerSocket serverSocket=new ServerSocket(8888);

System.out.println("服务器端Socket创建成功");

而(真)

{

System.out.println("等待客户端的连接请求");

//等待客户端连接请求

套接字socket=serverSocket.accept();

System.out.println("与客户端的连接成功建立");

}

}

捕获(IOException e)

{

e.printStackTrace();

}

}如上面代码所示,服务器端8888端口的socket建立成功后,如果没有客户端的连接请求,则accept()方法为空,所以“与客户端的连接建立成功”将不会被输出。运行结果如下图所示。

服务端S.ocket创建成功

等待客户端的连接请求

Socket 类

Socket 类表示通信双方中的客户端,用于呼叫远端机器上的一个端口,主动向服务器端发送数据(当连接建立后也能接收数据)。

Socket 的构造方法

Socket的构造方法如下。

Socket():无参构造方法。 Socket(InetAddress address,int port):创建一个流套接字并将其连接到指定IP地址的指定端口。 Soclcet(InetAddress address,int port,InetAddress localAddr,int localPort):创建套接字并将其连接到指定远程地址上的指定远程端口。 Socket(String host,int port):创建一个流套接字并将其连接到指定主机上的指定端口。 Socket(String host,int port,InetAddress localAddr,int localPort):创建一个套接字并将其连接到指定远程地址上的指定远程端口。 Socket将通过调用bind()函数绑定提供的本地地址和端口。上述方法的参数中,address为远程地址,port为远程端口,localAddr为socket绑定的本地地址,localPort为socket绑定的本地地址。本地端口。

Socket 的常用方法

Socket的常用方法如下。

voidbind(SocketAddressbindpoint):将套接字绑定到本地地址。 void close():关闭此套接字。 void connect(SocketAddress endpoint):将此套接字连接到服务器。 InetAddress getInetAddress():返回套接字的连接地址。 InetAddress getLocalAddress():获取绑定到套接字的本地地址。 InputStream getInputStream():返回此套接字的输入流。 OutputStream getOutputStream():返回此套接字的输出流。 SocketAddress getLocalSocketAddress():返回绑定到该套接字的端点地址,如果尚未绑定则返回null。 SocketAddress getRemoteSocketAddress():返回此套接字已连接的端点地址,如果尚未连接则返回null。 int getLoacalPort():返回绑定到此套接字的本地端口。 intgetPort():返回此套接字连接的远程端口。编写一个TCP程序,包括客户端和服务器端。要求服务器等待接收客户端发送的内容,然后将接收到的内容输出到控制台并进行反馈。

(1) 创建一个类作为客户端,首先在main()方法中定义一个Socket对象、一个OutputStream对象和一个InputStream对象并完成初始化。然后定义服务器的IP地址和端口号。代码如下。

公共静态无效主(字符串[] args){

套接字套接字=空;

输出流输出=空;

输入流=null;

String serverIP="127.0.0.1"; //服务器IP地址

国际端口=5000; //服务器端口号

}(2) 与服务器建立连接并向服务器发送数据。代码如下。

socket=new Socket(服务器IP,端口); //建立连接

out=socket.getOutputStream(); //发送数据

out.write("我是客户端数据".getBytes());(3) 从输入流中读取服务器的反馈信息,并输出到控制台。代码如下。

byte[] b=新字节[1024];

in=socket.getInputStream();

int len=in.read(b);

System.out.println("服务器的反馈为:"+new String(b,0,len));(4)关闭输入输出流和Socket对象,代码如下。

附寄();

关闭();

插座

.close();(5) 创建一个类作为服务器端,编写 main() 方法,创建 ServerSocket、Socket、InputStream、OutputStream 以及端口号并初始化,代码如下所示。 ServerSocket ServerSocket=null; Socket socket=null; InputStream in=null; OutputStream out=null; int port=5000;(6) 开启服务器并接收客户端发送的数据,代码如下所示。 ServerSocket=new ServerSocket(port); //创建服务器套接字 System.out.println("服务器开启,等待连接。。。"); socket=ServerSocket.accept(); //获得连接 //接收客户端发送的内容 in=socket.getInputStream(); byte[] b=new byte[1024]; int len=in.read(b); System.out.println("客户端发送的内容为:"+new String(b,0,len));(7) 使用输出流对象将信息反馈给客户端,代码如下所示。 out=socket.getOutputStream(); out.write("我是服务器端".getBytes());(8) 关闭输入/输出流、Socket 对象以及 ServerSocket 对象,代码如下所示。 in.close(); out.close(); ServerSocket.close(); socket.close();(9) 运行服务器端程序代码,运行结果如下所示。 服务器开启,等待连接。。。(10) 为了使程序的结果更加清晰,在步骤 (2) 的代码最后加入一句代码“Thread.sleep(1000);”。接着运行客户端程序代码,刚开始会出现如下所示的运行结果。 服务器开启,等待连接。。。 客户端发送的内容为:我是客户端数据紧接着又会出现如下所示的运行结果。 客户端的反馈为:我是服务器端

客户端与服务器端的简单通信

在了解 TCP 通信中 ServerSocket 类和 Socket 类的简单应用之后,本节将编写一个案例实现客户端向服务器发送信息,服务器读取客户端发送的信息,并将读取的数据写入到数据流中。 首先来看一下客户端的代码,如下所示: public class SocketDemo { public static void main(String[] args) { Socket socket=null; PrintWriter out=null; BufferedReader in=null; String serverIP="127.0.0.1"; //服务器端ip地址 int port=5000; //服务器端端口号 try { socket=new Socket(serverIP,port); in=new BufferedReader(new InputStreamReader(socket.getInputStream())); out=new PrintWriter(socket.getOutputStream(),true); while(true) { int number=(int)(Math.random()*10)+1; System.out.println("客户端正在发送的内容为:"+number); out.println(number); Thread.sleep(2000); } } catch(IOException | InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } }如上述代码所示,客户端代码主要是使用 Socket 连接 IP 为 127.0.0.1(本机)的 5000 端口。在建立连接之后将随机生成的数字使用 PrintWriter 类输出到套接字。休眠 2 秒后,再次发送随机数,如此循环。 再来看一个服务器端的代码,如下所示: package ch16; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket;

public class SocketDemoServer1 { public static void main(String[] args) { ServerSocket serverSocket=null; Socket clientSocket=null; BufferedReader in=null; int port=5000; String str=null; try { serverSocket=new ServerSocket(port); //创建服务器套接字 System.out.println("服务器开启,等待连接。。。"); clientSocket=serverSocket.accept();// 获得链接 //接收客户端发送的内容 in=new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); while(true) { str=in.readLine(); System.out.println("客户端发送的内容为:"+str); Thread.sleep(2000); } } catch(IOException | InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } }如上述代码所示,服务器端与客户端代码类似,首先使用 ServerSocket 在 IP为127.0.0.1(本机)的 5000 端口建立套接字监听。在 accept() 方法接收到客户端的 Socket 实例之后调用 BufferedReader 类的 readLine() 方法,从套接字中读取一行作为数据,再将它输出到控制后休眠 2 秒。 要运行本案例,必须先执行服务器端程序,然后执行客户端程序。客户端每隔 2 秒向服务器发送一个数字,如下所示。 客户端正在发送的内容为:10 客户端正在发送的内容为:5 客户端正在发送的内容为:10 客户端正在发送的内容为:4 客户端正在发送的内容为:3服务器端会将客户端发送的数据输出到控制台,如下所示。 服务器幵启,等待连接。。。客户端发送的内容为:7客户端发送的内容为:2客户端发送的内容为:10客户端发送的内容为:5客户端发送的内容为:10......

传输对象数据

经过前面的学习,掌握了如何在服务器开始一个端口监听套接字,以及如何在客户端连接服务器,发送简单的数字。 本次案例将实现如何在客户端发送一个对象到服务器端,服务器如何解析对象中的数据。 第一步是创建用于保存数据的类。这里使用的 User 类是一个普通的类,包含 name 和 password 两个成员。由于需要序列化这个对象以便在网络上传输,所以需要实现 java. io.Serializable 接 P。 User 类的代码如下: package ch16; public class User implements java.io.Serializable { private String name; private String password; public User(String name,String password) { this.name=name; this.password=password; } public String getName() { return name; } public void setName(String name) { this.name=name; } public String getPassword() { return password; } public void setPassword(String password) { this.password=password; } }接下来编写服务器端的代码。服务器的作用是接收客户端发送过来的数据,将数据转换成 User 对象并输出成员信息,然后对 User 对象进行修改输出给客户端。 服务器端 MyServer 类的实现代码如下: package ch16; import java.io.BufferedInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; public class MyServer { public static void main(String[] args) throws IOException { // 监听10000端口 ServerSocket server=new ServerSocket(10000); while(true) { //接收客户端的连接 Socket socket=server.accept(); //调用客户端的数据处理方法 invoke(socket); } } private static void invoke(final Socket socket) throws IOException { //开启一个新线程 new Thread(new Runnable() { public void run() { //创建输入流对象 ObjectInputStream is=null; //创建输出流对象 ObjectOutputStream os=null; try { is=new ObjectInputStream(socket.getInputStream()); os=new ObjectOutputStream(socket.getOutputStream()); //读取一个对象 Object obj = is.readObject(); //将对象转换为User类型 User user=(User) obj; //在服务器端输出name成员和password成员信息 System.out.println("user: "+user.getName()+"/"+user.getPassword()); //修改当前对象的name成员数据 user.setName(user.getName()+"_new"); //修改当前对象的password对象数据 user.setPassword(user.getPassword()+"_new"); //将修改后的对象输出给客户端 os.writeObject(user); os.flush(); } catch(IOException|ClassNotFoundException ex) { ex.printStackTrace(); } finally { try { //关闭输入流 is.close(); //关闭输出流 os.close(); //关闭客户端 socket.close(); } catch(Exception ex){} } } }).start(); } }如上述代码所示,在服务器端分别使用 ObjectInputStream 和 ObjectOutputStream 来接收和发送 socket 中的 InputStream 和OutputStream,然后转换成 User 对象。 客户端需要连接服务器,接收服务器输出的数据并解析,同时需要创建 User 对象并发给服务器。客户端 MyClient 类的实现代码如下: package ch16; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; public class MyClient { public static void main(String[] args) throws Exception { //循环100次 for(int i=0;i<100;i++) { //创建客户端Socket Socket socket=null; //创建输入流 ObjectOutputStream os=null; //创建输出流 ObjectInputStream is=null try { //连接服务器 socket=new Socket("localhost",10000); //接收输出流中的数据 os=new ObjectOutputStream(socket.getOutputStream()); //创建一个User对象 User user=new User("user_"+i,"password_"+i); //将User对象写入输出流 os.writeObject(user); os.flush(); //接收输入流中的数据 is=new ObjectInputStream(socket.getInputStream()); //读取输入流中的数据 Object obj=is.readObject(); //如果数据不空则转换成User对象,然后输出成员信息 if(obj!=null) { user=(User) obj; System.out.println("user: "+user.getName()+"/"+user.getPassword()); } } catch(IOException ex) { ex.printStackTrace(); } finally { try { //关闭输入流 is.close(); //关闭输出流 os.close(); //关闭客户端 socket.close(); } catch(Exception ex) {} } } } }仔细观察上述代码可以发现,客户端与服务器端的代码类似,同样使用 ObjectOutputStream 和 ObjectInputStream 来处理数据。 先运行服务器端程序 MyServer,再运行客户端程序 MyClient。此时将在客户端看到下所示的输出。 user:user_86_nevj/password_86_new user:user_87_new/password_87_new

user:user_88_new/password_88_new user:user_89_new/password_89_new user:user_90_new/password_90_new user:user_91_new/password_91_new user:user_92_new/password_92_new user:user_93_new/password_93_new user:user_94_new/password_94_new user:user_95_new/password_95_new user:user_96_new/password_96_new user:user_97_new/password_97_new user:user_98_new/password_98_new user:user_99_new/password_99_new服务器端的输出如下所示。 user:user_86/password_86 user:user_87/password_87 user:user_88/password_88 user:user_89/password_89 user:user_90/password_90 user:user_91/password_91 user:user_92/password_92 user:user_93/password_93 user:user_94/password_94 user:user_95/password_95 user:user_96/password_96 user:user_97/password_97 user:user_98/password_98 user:user_99/password_99

Java UDP通信:Java DatagramSocket类和DatagramPacket类

在 TCP/IP 协议的传输层除了一个 TCP 协议之外,还有一个 UDP 协议。UDP 协议是用户数据报协议的简称,也用于网络数据的传输。虽然 UDP 协议是一种不太可靠的协议,但有时在需要较快地接收数据并且可以忍受较小错误的情况下,UDP 就会表现出更大的优势。 下面是在 Java 中使用 UDP 协议发送数据的步骤。 使用 DatagramSocket() 创建一个数据包套接字。使用 DatagramPacket() 创建要发送的数据包。使用 DatagramSocket 类的 send() 方法发送数据包。接收 UDP 数据包的步骤如下: 使用 DatagramSocket 创建数据包套接字,并将其绑定到指定的端口。使用 DatagramPacket 创建字节数组来接收数据包。使用 DatagramPacket 类的 receive() 方法接收 UDP 包。

DatagramPacket 类

java.net 包中的 DatagramPacket 类用来表示数据报包,数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。下表简单介绍了 DatagramPacket 的构造方法和常用方法。 构造方法说明DatagramPacket(byte[] buf,int length)构造 DatagramPacket,用来接收长度为 length 的数据包。DatagramPacket(byte[] buf,int offset, int length)构造 DatagramPacket,用来接收长度为 length 的包,在缓 冲区中指定了偏移量。DatagramPacket(byte[] buf,int length, InetAddress address,int port)构造 DatagramPacket,用来将长度为 length 的包发送到指 定主机上的指定端口。DatagramPacket(byte[] buf,int length, SocketAddress address)构造数据报包,用来将长度为 length 的包发送到指定主机上 的指定端口。DatagramPacket(byte[] buf,int offset, int length,InetAddress address,int port)构造 DatagramPacket,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口。DatagramPacket(byte[] buf,int offset, int length,SocketAddress address)构造数据报包,用来将长度为 length、偏移量为 offset 的包发 送到指定主机上的指定端口。方法说明InetAddress getAddress()返回某台机器的 IP 地址,此数据报将要发往该机器或者 从该机器接收。byte[] getData()返回数据缓冲区。int getLength()返回将要发送或者接收的数据的长度。int getOffset()返回将要发送或者接收的数据的偏移量。int getPort()返回某台远程主机的端口号,此数据报将要发往该主机或 者从该主机接收。getSocketAddress()获取要将此包发送或者发出此数据报的远程主机的 SocketAddress(通常为 IP地址+端口号)。void setAddress(InetAddress addr)设置要将此数据报发往的目的机器的IP地址。void setData(byte[] buf)为此包设置数据缓冲区。void setData(byte[] buf,int offset, int length)为此包设置数据缓冲区。void setLength(int length)为此包设置长度。void setPort(int port)设置要将此数据报发往的远程主机的端口号。void setSocketAddress(SocketAddress address)设置要将此数据报发往的远程主机的 SocketAddress(通常为 IP地址+端口号)。

DatagramSocket 类

DatagramSocket 类用于表示发送和接收数据报包的套接字。数据报包套接字是包投递服务的发送或接收点。每个在数据报包套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。 DatagramSocket 类的常用构造方法如表所示。 构造方法说明DatagramSocket()构造数据报包套接字并将其绑定到本地主机上任何可用的端口。DatagramSocket(int port)创建数据报包套接字并将其绑定到本地主机上的指定端口。DatagramSocket(int portJnetAddress addr)创建数据报包套接字,将其绑定到指定的本地地址。DatagramSocket(SocketAddress bindaddr)创建数据报包套接字,将其绑定到指定的本地套接字地址。DatagramSocket 类的常用方法如表 所示。 方法说明void bind(SocketAddress addr)将此 DatagramSocket 绑定到特定的地址和端口。void close()关闭此数据报包套接字。void connect(InetAddress address,int port)将套接字连接到此套接字的远程地址。void connect(SocketAddress addr)将此套接子连接到远程套接子地址(IP地址+端口号)。void disconnect()断开套接字的连接。InetAddress getInetAddress()返回此套接字连接的地址。InetAddress getLocalAddress()获取套接字绑定的本地地址。int getLocalPort()返回此套接字绑定的本地主机上的端口号。int getPort()返回此套接字的端口。编写 UDP 程序,要求客户端程序可以向服务器端发送多条数据,服务器端程序可以接收客户端发送的多条数据并将其信息输出在控制台,主要步骤如下所示。 (1) 创建一个类作为客户端,在 main() 方法定义一个 DatagramSocket 对象和一个 DatagramPacket 对象并初始化为 null。然后再定义一个 InetAddress 对象和一个端口号并分别进行初始化,代码如下所示。 public static void main(String[] args) { DatagramSocket ds=null; DatagramPacket dpSend=null; InetAddress ia=InetAddress.getByName("127.0.0.1"); int port=3021; }(2) 使用 DatagramSocket 的 send(DatagramPacket p) 方法向服务器端发送数据报包,使用循环的方式完成 5 次数据的发送,每发送 1 次数据线程休眠 1000 毫秒,数据发送完毕调用 close() 方法,关闭 DatagramSocket 对象,代码如下。 try { ds=new DatagramSocket(); for(int i=0;i<5;i++) { byte[] data=("我是 UDP 客户端"+i).getBytes(); dpSend=new DatagramPacket(data,data.length,ia,port); ds.send(dpSend); Thread.sleep(1000); } ds.close(); } catch(IOException | InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); }(3) 创建一个类作为服务器端,在 main() 方法中定义一个 DatagramSocket 对象和一个 DatagramPacket 对象并初始化为 null,再定义一个端口号,如下所示。 public static void main(String[] args) { DatagramSocket ds=null; DatagramPacket dpReceive=null; int port=3021; }(4) 如果成功连接到 UDP 服务器则输出“UDP 服务器已启动。”。循环接收客户端发送的数据,并将其发送的内容以及IP地址等信息输出到控制台,代码如下所示。 try { ds=new DatagramSocket(port); System.out.println("UDP服务器已启动。。。"); byte[] b=new byte[1024]; while(ds.isClosed()==false) { dpReceive=new DatagramPacket(b, b.length); try { ds.receive(dpReceive); byte[] Data=dpReceive.getData(); int len=Data.length; System.out.println("UDP客户端发送的内容是:" + new String(Data, 0, len).trim()); System.out.println("UDP客户端IP:" + dpReceive.getAddress()); System.out.println("UDP客户端端口:" + dpReceive.getPort()); } catch(IOException e) { e.printStackTrace(); } } } catch(SocketException e1) { // TODO 自动生成的 catch 块 e1.printStackTrace(); } }(5) 最后关闭 DatagramSocket 对象。执行服务器端程序,运行结果如下所示。 UDP服务器已启动。。。(6) 再运行客户端程序,控制台的输出结果如下所示。 UDP客户端发送的内容是:我是UDP客户端0 UDP客户端IP:/127.0.0.1 UDP客户端端口:53472 UDP客户端发送的内容是:我是UDP客户端1 UDP客户端IP:/127.0.0.1 UDP客户端端口:53472 UDP客户端发送的内容是:我是UDP客户端2 UDP客户端IP:/127.0.0.1 UDP客户端端口:53472 UDP客户端发送的内容是:我是UDP客户端3 UDP客户端IP:/127.0.0.1 UDP客户端端口:53472 UDP客户端发送的内容是:我是UDP客户端4 UDP客户端IP:/127.0.0.1 UDP客户端端口:53472

什么是URL?及URL类和URLConnection类

在 Java 的 API 中的 java.net 包中包含一个 URL 类和一个 URLConnection 类。

URL 概念

URL 是统一资源定位符(Uniform Resource Locator)的简称,它表示 Internet 上某一资源的地址。通过 URL 用户可以访问各种网络资源,比如常见的 WWW 以及 FTP 站点。浏览器可以通过解析给定的 URL 在网络上查找相应的文件或其他资源。 URL 的语法格式如下所示。 protocol://resourceName协议名(protocol)指明获取资源所使用的传输协议,如 HTTP、FTP 和 file 等,资源名(resourceName)则应该是资源的完整地址,包括主机名、端口号、文件名或文件内部的一个引用。下面是一些简单的 URL 示例。 http://www.sun.com/ 协议名://主机名 http://localhost:8080/Test/admin/login.jsp 协议名://机器名:端口号/文件名

URL 类

在 java.net 包中包含专门用来处理 URL 的类 URL,可以获得 URL 的相关信息,例如 URL 的协议名和主机名等。 构造方法说明public URL (String spec)通过一个表示 URL 地址的字符串可以构造一个 URL 对象。public URL(URL context,String spec)使用基本地址和相对 URL 构造一个 URL 对象。public URL(String protocol,String host,String file)使用指定的协议、主机名和文件名创建一个 URL 对象。public URL(String protocol,String host,int port,String file)使用指定的协议、主机名、端口号和文件名创建一个 URL 对象。URL 的常用方法如表所示。 方法说明public String getProtocol()获取该 URL 的协议名。public String getHost()获取该 URL 的主机名。public int getPort()获取该 URL 的端口号,如果没有设置端口,返回 -1。public String getFile()获取该 URL 的文件名。public String getRef()获取该 URL 在文件中的相对位置。public String getQuery()获取该 URL 的查询信息。public String getPath()获取该 URL 的路径。public String getAuthority()获取该 URL 的权限信息。public String getUserInfo()获得使用者的信息。public String getRef()获得该 URL 的锚点。

URLConnection 类

完成了 URL 的定义,接下来就可以获得 URL 的通信连接。在 java.net 包中,定义了专门的 URLConnection 类来表示与 URL 建立的通信连接,URLConnection 类的对象使用 URL 类的 openConnection() 方法获得。 URLConnection 类的主要方法如表所示。 方法说明void addRequestProperty(String key,String value)添加由键值对指定的一般请求属性。key 指的是用于识别请求的关键字 (例如 accept),value 指的是与该键关联的值。void connect()打开到此 URL 所引用的资源的通信链接(如果尚未建立这样的链接)。Object getConnection()检索此 URL 链接的内容。InputStream getInputStream()返回从此打开的链接读取的输入流。OutputStream getOutputStream()返回写入到此链接的输出流。URL getURL()返回此 URLConnection 的 URL 字段的值。例 使用 URL 和 URLConnection 类获取与百度首页的链接并将其页面信息输出到控制台,主要步骤如下所示。 (1) 创建一个类,编写 main() 方法,在该方法中创建一个 URL 对象,然后传入参数“http://www.baidu.com/”,输出 URL 的相关信息,代码如下所示。 package ch16; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; public class URLDemo { public static void main(String[] args) { try { URL url=new URL("http://www.baidu.com/"); System.out.println("协议:" + url.getProtocol()); System.out.println("主机:" + url.getHost()); System.out.println("端口:" + url.getPort()); InputStream in; } catch(IOException e) { //TODO 自动生成的 catch 块 e.printStackTrace(); } } }(2) 在 main() 方法的 try 模块中继续添加代码,获得 URLConnection 对象,通过输入流读取页面源代码并将信息输出到控制台,代码如下所示。 URLConnection uc=url.openConnection(); in=uc.getInputStream(); byte[] b=new byte[1024]; int len; while((len=in.read(b))!=-1) { System.out.println(new String(b,0,len)); } in.close();(3) 运行程序,执行结果如下所示。 协议:http 主机:www.baidu.com 端口:-1

提取 URL 协议名称

我们知道 URL 中必须有一个协议名称,常用的协议有 HTTP、HTTPS 和 FTP 等。本实例将允许用户输入一个 URL,然后从中提取出协议名称。 实例代码如下: package ch16; import java.net.MalformedURLException; import java.net.URL; import java.util.Scanner; public class URLDemo1 { public static void main(String[] args) { try { Scanner scan=new Scanner(System.in); //创建输入扫描器 System.out.println("请输入一个完整的网址:"); String line=scan.nextLine(); //获取用户输入文本 URL url=new URL(line); //创建URL对象 System.out.println("这个网址的主机名称是:"+url.getHost()); //获取主机名称 System.out.println("这个网址的URL协议名称是:"+url.getProtocol()); //获取协议名称 } catch(MalformedURLException e) { System.out.println("输入的是非法网址"); //提示错误信息 } } }如上述代码所示,在创建一个 URL 类对象之后调用 getHost() 方法获取主机名称,调用 getPmtocol() 方法获取协议名称。实例运行结果如下所示。 请输入一个完整的网址: http://www.baidu.com 这个网址的主机名称是:www.baidu.com 这个网址的URL协议名称是:http 请输入一个完整的网址: ftp://www.baidu.com/seo 这个网址的主机名称是:www.baidu.com

好了,本文到此结束,如果可以帮助到大家,还望关注本站哦!

用户评论

巷雨优美回忆

准备好好学习Java基础,对未来有更多期待。

    有15位网友表示赞同!

话少情在

一直想入行互联网,这次趁机把Java基础和网络编程补起来。

    有17位网友表示赞同!

有恃无恐

2020年是新的开始,给自己一个目标吧!学好Java.

    有10位网友表示赞同!

请在乎我1秒

对于入门程序员来说,这确实是个不错的学习方向。

    有16位网友表示赞同!

追忆思域。

Java基础太重要了,想将来开发自己的APP需要这个!

    有10位网友表示赞同!

箜明

网络编程听起来很酷炫啊,感觉自己能做一些厉害的东西。

    有5位网友表示赞同!

身影

希望课程能够比较系统地讲解,让我一步步深入学习。

    有6位网友表示赞同!

泡泡龙

我已经开始关注一些Java相关的资料了,准备迎接挑战!

    有18位网友表示赞同!

命该如此

这个计划很有目标性,2020年要努力提升自己。

    有17位网友表示赞同!

无关风月

以前对Java基础了解的不多,希望通过这次学习能掌握核心知识.

    有20位网友表示赞同!

ー半忧伤

网络编程和JAVA相结合,想想就觉得很有趣!

    有17位网友表示赞同!

红尘滚滚

期待课程开启,开始新的学习旅程!

    有12位网友表示赞同!

冷嘲热讽i

2020年要好好抓住机会,努力学习提升自己。

    有6位网友表示赞同!

最迷人的危险

感觉Java基础知识在未来的就业市场还是比较受欢迎的。

    有14位网友表示赞同!

巴黎盛开的樱花

准备买点好耳机,沉浸式学习Python和Java!

    有9位网友表示赞同!

【2020新征程:JAVA基础与网络编程学习指南】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活