目录
示例4-2: 模拟客户咨询问题(升级4-1,接收回应咨询信息)
01、查看IP地址
1、认识网络
1.1、网络概述
网络:连接在一起共享数据和资源的一组计算机
1.2、分类(按照地理覆盖范围)
1)局域网
局域网(LAN)局限在小的地理区域或单独的建筑物内,被用于连接公司办公室、实验室或工厂里的个人计算机和工作站。
2)城域网
城域网(MAN)覆盖城市或城镇内的广大地理区域,是在一个城市范围内所建立的计算机通信网。
3)广域网
广域网(WAN)是在一个更广泛的地理范围内所建立的计算机通信网,其范围可以超越城市和国家以至全球,因而对通信的要求和复杂性都比较高。
1.3、网络分层模型
2、IP地址
2.1、IP地址概述
2.2、IP地址的组成和分类
2.3、IP地址的配置和检测
3、重要概述介绍
3.1、端口
3.2、域名与DNS域名解析
3.3、网络服务器
3.4、网络通信协议
02、实现基于TCP协议的Socket编程
1、认识Socket
1.1、Socket概述
在计算机网络编程技术中,两个进程或者说两台计算机可以通过一个网络通信连接实现数据的交换,这种通信链路的端点就称为“套接字”(英文名称也就是Socket),Socket是网络驱动层提供给应用程序的一个接口或者说一种机制。
以下述物流送快递的例子来说明Socket.
1.2、Socket通信原理
Socket的底层机制非常复杂,Java平台提供了一些虽然简单但是相当强大的类,可以有效的使用Socket开发通信程序而无需了解底层机制。
1.3、java.net包
java.net包中常用的类:
(1)Socket
(2)ServerSocket:监听客户端的连接请求,用于实现网络上进程间通信的套接字
(3)DatagramPacket:使用DatagramScoket类的对象封装和收到的数据报
(4)DatagramSocket:使用UDP协议实现客户端和服务器套接字
(5)InetAddress:表示Internet地址,可在创建数据报报文和Socket对象时使用
(6)URLConnection
(7)URLEncoder
2、基于TCP协议的Socket编程
进行网络通信时,Socket需要借助数据流来完成数据的传递工作。如果一个应用程序要通过网络向另一个应用程序发送数据,只要简单地创建Socket,然后将数据写入到与该Socket关联的输出流即可。对应的,接收方的应用程序创建Socket,从相关联的输入流读取数据即可。以下为Socket通信模型:
3、使用Socket编程实现登陆功能
示例1-1:实现单用户登陆(采用字符串的形式传递数据)
需求说明:
模拟用户登陆的功能,实现客户端发送用户登陆信息,服务器端显示登陆信息并响应给客户端登陆成功。
(1)客户端实现步骤:
(1)建立客户端Socket连接,连接指向服务器及端口
(2)获取输出流将登陆信息发送给服务器端
(3)发送客户端登陆信息,即向输出流中写入信息
(4)写入信息
(5)关闭输出流
(6)获取输入流接收服务器端发送的响应信息
(7)关闭所有的数据流(2)客户端实现步骤:
(1)建立连接,监听端口
(2)使用accept()方法等待客户端发起通信请求
(3)获取输入流接收客户端的请求信息
(4)获取输出流向客户端发送相应信息
(5)关闭所有流(原则:先开的后关,后开的先关)(3)客户端代码实现:Client
package cn.bdqn.demo01; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class Client { public static void main(String[] args) throws UnknownHostException, IOException { /* * 1.实现单用户登陆 * 示例1: * 模拟用户登陆的功能,实现客户端发送用户登陆信息,服务器端显示登陆信息并响应给客户端登陆成功。 * 客户端实现步骤: * (1)建立客户端Socket连接,连接指向服务器及端口 * (2)获取输出流将登陆信息发送给服务器端 * (3)发送客户端登陆信息,即向输出流中写入信息 * (4)写入信息 * (5)关闭输出流 * (6)获取输入流接收服务器端发送的响应信息 * (7)关闭所有的数据流 * 服务端实现步骤: * (1)建立连接,监听端口 * (2)使用accept()方法等待客户端发起通信请求 * (3)获取输入流接收客户端的请求信息 * (4)获取输出流向客户端发送相应信息 * (5)关闭所有流(原则:先开的后关,后开的先关) * */ //(1)建立客户端Socket连接,指定服务器的位置为本机以及端口为8800 Socket socket = new Socket("localhost", 8800); //(2)获取输出流将登陆信息发送给服务器端 OutputStream os = socket.getOutputStream(); //(3)发送客户端登陆信息,即向输出流中写入信息 String str = "用户名:Tom,密码:123456"; //(4)写入信息 os.write(str.getBytes());//注:getBytes()方法为String类方法:使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中 System.out.println("向服务器发送请求成功!"); //(5)关闭输出流 socket.shutdownOutput(); //(6)获取输入流接收服务器端发送的响应信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String str1; while((str1=br.readLine())!=null){ System.out.println("这里是客户端,接收到的服务器发来的响应信息为:"+str1); } //(7)关闭所有流(原则:先开的后关,后开的先关) br.close(); is.close(); os.close(); socket.close(); } }
(4)服务器端代码实现:Server
package cn.bdqn.demo01; 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 Server { public static void main(String[] args) throws IOException { /* * 1.实现单用户登陆 * 示例1: * 模拟用户登陆的功能,实现客户端发送用户登陆信息,服务器端显示登陆信息并响应给客户端登陆成功。 * * 客户端实现步骤: * (1)建立客户端Socket连接,连接指向服务器及端口 * (2)获取输出流将登陆信息发送给服务器端 * (3)发送客户端登陆信息,即向输出流中写入信息 * (4)写入信息 * (5)关闭输出流 * (6)获取输入流接收服务器端发送的响应信息 * (7)关闭所有的数据流 * 服务端实现步骤: * (1)建立连接,监听端口 * (2)使用accept()方法等待客户端发起通信请求 * (3)获取输入流接收客户端的请求信息 * (4)获取输出流向客户端发送相应信息 * (5)关闭所有流(原则:先开的后关,后开的先关) * */ //(1)建立一个服务器Socket(ServerSocket),指定端口8800并开始监听 ServerSocket ss = new ServerSocket(8800); //(2)使用accept()方法等待客户端发起通信请求 Socket soc = ss.accept(); //(3)获取输入流接收客户端的请求信息 InputStream is = soc.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String str; while((str=br.readLine())!=null){ System.out.println("这里是服务器端,接收到的客户端信息为:"+str); } //(4)获取输出流向客户端发送相应信息 OutputStream os = soc.getOutputStream(); String str1="用户名和密码正确,登录成功"; os.write(str1.getBytes()); //(5)关闭所有流(原则:先开的后关,后开的先关) os.close(); br.close(); is.close(); soc.close(); ss.close(); } }
(5)客户端和服务器端输出结果:
示例1-2:实现单用户登陆(采用对象的形式传递数据)
需求说明:
模拟用户登陆的功能,实现客户端发送用户登陆信息,服务器端显示登陆信息并响应给客户端登陆成功。
(1)实体类代码:User
package cn.bdqn.demo02; import java.io.Serializable; /** * 示例02:升级演示示例01,实现传递对象信息 * 在示例1中,传递的数据均采用字符串的形式,而Java语言是面向对象的,如何在Socket * 中实现对象的传递呢?下面的示例2将升级示例1,把字符串的数据修改为对象来传递。 */ public class User implements Serializable{ private static final long serialVersionUID = 1L; private String loginName;//用户名 private String pwd;//用户密码 //无参构造方法 public User() { super(); } //有参构造方法 public User(String loginName, String pwd) { super(); this.loginName = loginName; this.pwd = pwd; } //getter()和setter()方法 public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public static long getSerialversionuid() { return serialVersionUID; } }
(2)客户端代码:LoginClient
package cn.bdqn.demo02; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class LoginClient { /** * 示例02:升级演示示例01,实现传递对象信息 在示例1中,传递的数据均采用字符串的形式,而Java语言是面向对象的,如何在Socket * 中实现对象的传递呢?下面的示例2将升级示例1,把字符串的数据修改为对象来传递。 */ public static void main(String[] args) throws UnknownHostException, IOException { // 建立客户端Socket连接,指定服务器的位置为本机以及端口为8800 Socket socket = new Socket("localhost", 8800); // 打开输出流 OutputStream os = socket.getOutputStream(); // 对象序列化 ObjectOutputStream oos = new ObjectOutputStream(os); // 发送客户端信息,即向输出流中写入信息 User user = new User("Tom", "123456"); oos.writeObject(user); socket.shutdownOutput(); // 关闭输出流 // 接收服务器端信息,即从输入流中读取信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String reply; while ((reply = br.readLine()) != null) { System.out.println("我是客户端,服务器的响应为:" + reply); } br.close(); is.close(); oos.close(); os.close(); socket.close(); } }
(3)服务器端代码:
package cn.bdqn.demo02; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class LoginServer { /** * 示例02:升级演示示例01,实现传递对象信息 在示例1中,传递的数据均采用字符串的形式,而Java语言是面向对象的,如何在Socket * 中实现对象的传递呢?下面的示例2将升级示例1,把字符串的数据修改为对象来传递。 */ public static void main(String[] args) throws IOException, ClassNotFoundException { // 建立一个服务器Socket(ServerSocket),指定端口8800并开始监听 ServerSocket serverSocket = new ServerSocket(8800); // 使用accept()方法等待客户端发起通信 Socket socket = serverSocket.accept(); // 打开输入流 InputStream is = socket.getInputStream(); // 反序列化 ObjectInputStream ois = new ObjectInputStream(is); // 获取客户端信息,即从输入流读取信息 User user = (User) ois.readObject(); if (user != null) { System.out.println("我是服务器,客户登录信息为:" + user.getLoginName() + "," + user.getPwd()); } //给客户端一个响应,即向输出流中写入信息 String reply = "欢迎你,登录成功"; OutputStream os = socket.getOutputStream(); os.write(reply.getBytes()); os.close(); ois.close(); is.close(); socket.close(); serverSocket.close(); } }
(4)客户端和服务器端输出结果:
示例2:实现多客户端用户登陆
升级示例1-2,实现多客户端的响应处理。
分析如下:
1)创建服务器端线程类,run()方法中实现对一个请求的响应处理。
2)修改服务器端代码,让服务器端Socket一直处于监听状态。
3)服务器端每监听到一个请求,创建一个线程对象并启动(1)实现类代码:User
package cn.bdqn.demo01; import java.io.Serializable; /** * 示例03:升级示例2-1,实现多客户端的响应处理 * */ public class User implements Serializable{ private static final long serialVersionUID=1L; private String loginName;//用户名 private String pwd;//用户密码 public User() { super(); } public User(String loginName, String pwd) { super(); this.loginName = loginName; this.pwd = pwd; } public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public static long getSerialversionuid() { return serialVersionUID; } }
(2)线程类代码:LoginThread
package cn.bdqn.demo01; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.net.Socket; public class LoginThread extends Thread { /* * 示例03:升级示例2-1,实现多客户端的响应处理。 * * 分析如下: * (1)创建服务器端线程类,run()方法中实现对一个请求的响应处理。 * (2)修改服务器端代码,让服务器端Socket一直处于监听状态。 * (3)服务器端每监听到一个请求,创建一个线程对象并启动 */ Socket socket = null; //每启动一个线程,连接对应的socket public LoginThread(Socket socket){ this.socket = socket; } public void run(){ InputStream is = null; ObjectInputStream ois = null; OutputStream os = null; try { //打开输入流 is = socket.getInputStream(); //反序列化 ois = new ObjectInputStream(is); //获取客户端信息,即从输入流读取信息 User user = (User)ois.readObject(); if(user!=null){ System.out.println("我是服务器,客户登录信息为:"+user.getLoginName()+","+user.getPwd()); } //给客户端一个响应,即向输出流中写入信息 os = socket.getOutputStream(); String reply = "欢迎你,登陆成功"; os.write(reply.getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ try { os.close(); ois.close(); is.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
(3)服务器端代码:LoginServer
package cn.bdqn.demo01; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * 示例03:升级示例示例2-1,实现多客户端的响应处理 * */ public class LoginServer { public static void main(String[] args) throws IOException { //建立一个服务器Socket(ServerSocket),指定端口并开始监听 ServerSocket serverSocket = new ServerSocket(8800); //监听一直进行中 while(true){ //使用accpt()方法等待客户发起通信 Socket socket = serverSocket.accept(); LoginThread loginThread = new LoginThread(socket); loginThread.start(); } } }
(4)客户端 1 代码:LoginClient01
package cn.bdqn.demo01; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class LoginClient01 { public static void main(String[] args) throws UnknownHostException, IOException { //建立客户端Socket连接,指定服务器的位置为本机以及端口为8800 Socket socket = new Socket("localhost", 8800); //打开输出流 OutputStream os = socket.getOutputStream(); //对象序列化 ObjectOutputStream oos= new ObjectOutputStream(os); //发送客户端信息,即向输出流中写入信息 User user = new User("Tom", "123456"); oos.writeObject(user); socket.shutdownOutput(); //接收服务器端的响应,即从输入流中读取信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String reply; while((reply=br.readLine())!=null){ System.out.println("我是客户端,服务器的响应为:"+reply); } //关闭流 br.close(); is.close(); oos.close(); os.close(); socket.close(); } }
(5)客户端 2 代码:LoginClient02
package cn.bdqn.demo01; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class LoginClient02 { public static void main(String[] args) throws UnknownHostException, IOException { //建立客户端Socket连接,指定服务器的位置为本机以及端口为8800 Socket socket = new Socket("localhost", 8800); //打开输出流 OutputStream os = socket.getOutputStream(); //对象序列化 ObjectOutputStream oos= new ObjectOutputStream(os); //发送客户端信息,即向输出流中写入信息 User user = new User("Java", "456789"); oos.writeObject(user); socket.shutdownOutput(); //接收服务器端的响应,即从输入流中读取信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String reply; while((reply=br.readLine())!=null){ System.out.println("我是客户端,服务器的响应为:"+reply); } //关闭流 br.close(); is.close(); oos.close(); os.close(); socket.close(); } }
(6)客户端 3 代码:LoginClient03
package cn.bdqn.demo01; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class LoginClient03 { public static void main(String[] args) throws UnknownHostException, IOException { //建立客户端Socket连接,指定服务器的位置为本机以及端口为8800 Socket socket = new Socket("localhost", 8800); //打开输出流 OutputStream os = socket.getOutputStream(); //对象序列化 ObjectOutputStream oos= new ObjectOutputStream(os); //发送客户端信息,即向输出流中写入信息 User user = new User("Bob", "112233"); oos.writeObject(user); socket.shutdownOutput(); //接收服务器端的响应,即从输入流中读取信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String reply; while((reply=br.readLine())!=null){ System.out.println("我是客户端,服务器的响应为:"+reply); } //关闭流 br.close(); is.close(); oos.close(); os.close(); socket.close(); } }
(7)客户端和服务器端输出结果:
注:首先启动服务器端、之后再一次启动客户端
①启动客户端1:LoginClient01
② 启动客户端2:LoginClient02
③启动客户端3:LoginClient03
示例3:InetAddress类(输出本地主机的地址信息)
表 InetAddress类中的工厂方法 方法 说明 static InetAddress getLocalHost() 返回表示本地主机的InetAddress对象 static InetAddress getByName(String hostName) 返回指定主机名为hostName的InetAddress对象 static InetAddress[ ] getAllByName(String hostName) 返回主机名为hostName的所有可能的InetAddress对象组 代码实现:
package cn.bdqn.demo02; import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressTest { /* * 示例04:输出本机的地址信息 * * */ public static void main(String[] args) { try { //getLocalHost():返回表示本地主机的InetAddress对象 InetAddress add = InetAddress.getLocalHost(); System.out.println("本地主机的地址是:"+add); } catch (UnknownHostException e) { e.printStackTrace(); } } }
03、实现基于UDP协议的Socket编程
1、 使用Socket编程实现客户咨询
基于UDP协议的Socket网络编程一般按照以下4个步骤进行
(1)利用DatagramPacket对象封装数据报
(2)利用DatagramSocket对象发送数据报
(3)利用DatagramSocket对象接收数据报
(4)利用DatagramPacket对象处理数据报
示例4-1:模拟客户咨询问题
需求说明:
模拟客户咨询问题,实现发送方发送咨询问题,接收方接收并显示发送来的咨询问题。
(1)发送方实现步骤
1)获取本地主机的InetAddress对象。
2)创建DatagramPacket对象,封装要发送的信息。
3)利用DatagramSocket对象将DatagramPacket对象数据发送出去。(2)接收方实现步骤
1)创建DatagramPacket对象,准备接收封装的数据。
2)创建DatagramSocket对象,接收数据保存于DatagramPacket对象中。
3)利用DatagramPacket对象处理数据。(3)发送方代码:
package cn.bdqn.demo03; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; public class Send { /* * 示例05:模拟客户咨询问题,实现发送方发送咨询问题,接收方接收并显示发送来的咨询问题。 * * 发送方实现步骤如下: * (1)获取本地主机的InetAddress对象。 * (2)创建DatagramPacket对象,封装要发送的信息。 * (3)利用DatagramSocket对象将DatagramPacket对象数据发送出去。 */ public static void main(String[] args) throws IOException { String mess = "你好,我想咨询一个问题。"; //获取本地主机地址 InetAddress ia = InetAddress.getByName("localhost"); //创建DatagramPacket对象,封装数据 DatagramPacket dp = new DatagramPacket(mess.getBytes(), mess.getBytes().length, ia, 8800); //创建DatagramSocket对象,向服务器发送数据 DatagramSocket ds = new DatagramSocket(); ds.send(dp); ds.close(); } }
(4)接收方代码:
package cn.bdqn.demo03; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class Receive { /* * 示例05:模拟客户咨询问题,实现发送方发送咨询问题,接收方接收并显示发送来的咨询问题。 * * 接收方实现步骤如下: * (1)创建DatagramPacket对象,准备接收封装的数据。 * (2)创建DatagramSocket对象,接收数据保存于DatagramPacket对象中。 * (3)利用DatagramPacket对象处理数据。 */ public static void main(String[] args) throws IOException { //(1)创建DatagramPacket对象,用来准备接收数据 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, 1024); //(2)创建DatagramSocket对象,接收数据 DatagramSocket ds = new DatagramSocket(8800); ds.receive(dp); //显示接收到的信息 String mess = new String(dp.getData(), 0, dp.getLength()); System.out.println(dp.getAddress().getHostAddress()+"说:"+mess); //关闭流 ds.close(); } }
(5)接收方接收并显示发送来的咨询问题
示例4-2: 模拟客户咨询问题(升级4-1,接收回应咨询信息)
需求说明:
模拟客户咨询问题,实现发送方发送咨询问题,接收方回应咨询。
(1)发送方代码:
package cn.bdqn.demo04; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; public class Send { /* * 示例06:升级示例05,发送方发送咨询问题,接收方回应咨询。 * * 发送方实现步骤如下: * (1)获取本地主机的InetAddress对象。 * (2)创建DatagramPacket对象,封装要发送的信息。 * (3)利用DatagramSocket对象将DatagramPacket对象数据发送出去。 */ public static void main(String[] args) throws IOException { String mess = "你好,我想咨询一个问题。"; System.out.println("我说:"+mess); //获取本地主机地址 InetAddress ia = InetAddress.getByName("localhost"); //创建DatagramPacket对象,封装数据 DatagramPacket dp = new DatagramPacket(mess.getBytes(), mess.getBytes().length, ia, 8800); //创建DatagramSocket对象,向服务器发送数据 DatagramSocket ds = new DatagramSocket(); ds.send(dp); byte[] buf = new byte[1024]; DatagramPacket dpre = new DatagramPacket(buf, buf.length); ds.receive(dpre); //显示接收到的信息 String reply = new String(dpre.getData(), 0, dpre.getLength()); System.out.println(dpre.getAddress().getHostAddress()+"说:"+reply); ds.close(); } }
(2)接受方代码:
package cn.bdqn.demo04; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress; public class Receive { /* * 示例06:升级示例05,发送方发送咨询问题,接收方回应咨询。 * * 接收方实现步骤如下: (1)创建DatagramPacket对象,准备接收封装的数据。 * (2)创建DatagramSocket对象,接收数据保存于DatagramPacket对象中。 * (3)利用DatagramPacket对象处理数据。 */ public static void main(String[] args) throws IOException { // 创建DatagramPacket对象,用来准备接收数据 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, 1024); // 创建DatagramSocket对象,接收数据 DatagramSocket ds = new DatagramSocket(8800); ds.receive(dp); // 显示接收到的信息 String mess = new String(dp.getData(), 0, dp.getLength()); System.out.println(dp.getAddress().getHostAddress() + "说:" + mess); String reply = "你好,我在,请咨询!"; // 显示与本地对话框 System.out.println("我 说:" + reply); // 创建DatagramPacket对象,封装数据 SocketAddress sa = dp.getSocketAddress(); DatagramPacket dpto = new DatagramPacket(reply.getBytes(), reply.getBytes().length, sa); ds.send(dpto); ds.close(); } }
(3)发送方和接收方输出结果: