21.1网络程序设计基础
21.1.1 局域网与互联网
为了实现两台计算机的通信,必须用一个网络线路连接两台计算机。如下图所示
21.1.2 网络协议
1.IP协议
IP是Internet Protocol的简称,是一种网络协议。Internet 网络采用的协议是TCP/IP协议,其全称是Transmission Control Protocol/Internet Protocol。Internet 依靠TCP/IP协议,在全球范围内实现了不同硬件结构、不同操作系统、不同网络系统间的互联。在Internet 网络上存在着数以亿计的主机,每台主机都用网络为其分配的 Internet 地址代表自己,这个地址就是I地址。到目前为止,I地址用4个字节,也就是32位的二进制数来表示,称为IPv4。为了便于使用,通常取用每个字节的十进制数,并且每个字节之间用圆点隔开来表示I地址,如192.168.1.1。现在人们正在试验使用16个字节来表示I地址,这就是IPv6,但IPv6还没有投入使用。
TCP/IP 模式是一种层次结构,共分为4层,分别为应用层、传输层、互联网层和网络层。各层实现特定的功能,提供特定的服务和
2. TCP与UDP协议
在TCPAIP 协议栈中,有两个高级协议是网络应用程序编写者应该了解的,即传输控制协议(Transmission Control Protocol,TCP)与用户数据报协议(User Datagram Protocol, UDP)。
TCP 协议是一种以固接连线为基础的协议,它提供两台计算机间可靠的数据传送。TCP可以保证数据从一端送至连接的另一端时,能够确实送达,而且抵达的数据的排列顺序和送出时的顺序相同。因此,TCP协议适合可靠性要求比较高的场合。就像拨打电话,必须先拨号给对方,等两端确定连接后,相互才能听到对方说话,也知道对方回应的是什么。
HTTP、FTP 和Telnet 等都需要使用可靠的通信频道。例如,HTTP从某个URL读取数据时,如果收到的数据顺序与发送时不相同,可能就会出现一个混乱的HTML文件或是一些无效的信息。
UDP是无连接通信协议,不保证数据的可靠传输,但能够向若干个目标发送数据,或接收来自若干个源的数据。UDP以独立发送数据包的方式进行。这种方式就像邮递员送信给收信人,可以寄出很多信给同一个人,且每一封信都是相对独立的,各封信送达的顺序并不重要,收信人接收信件的顺服务器托管网序也不能保证与寄出信件的顺序相同。
UDP 协议适合于一些对数据准确性要求不高,但对传输速度和时效性要求非常高的网站,如网络聊天室、在线影片等。这是由于TCP协议在认证上存在额外耗费,可能使传输速度减慢,而UDP协议即使有一小部分数据包遗失或传送顺序有所不同,也不会严重危害该项通信。
21.1.3 端口与套接字
一般而言,一台计算机只有单一的连到网络的物理连接(Physical Connection),所有的数据都通过此连接对内、对外送达特定的计算机,这就是端口。网络程序设计中的端口(port)并非真实的物理存在,而是一个假想的连接装置。端口被规定为一个在0~65535的整数。HTTP服务一般使用80端口,FTP 服务使用21端口。假如一台计算机提供了HTTP、FTP等多种服务,那么客户机会通过不同的端口来确定连接到服务器的哪项服务上,如图所示。
通常,0~1023的端口数用于一些知名的网络服务和应用,用户的普通网络应用程序应该使用1024以上的端口数,以避免端口号与另一个应用或系统服务所用端口冲突。
网络程序中的套接字(Socket)用于将应用程序与端口连接起来。套接字是一个假想的连接装置,就像插座一样可连接电器与电线,如图所示。
Java 将套接字抽象化为类,程序设计者只需创建Socket类对象,即可使用套接字。
21.2 TCP程序
TCP网络程序设计是指利用Socket 类编写通信程序。利用TCP协议进行通信的两个应用程序是有主次之分的,一个称为服务器程序,另一个称为客户机程序,两者的功能和编写方法大不一样。服务器端与客户端的交互过程如图所示。
- 例题21.1
-
import java.net.*; //导出Java.net包 public class Address { //创建类 public static void main(String[] args) { InetAddress ip; //创建InetAddress对象 try { //捕捉可能出现的异常 ip = InetAddress.getLocalHost(); //实例化对象 String locaIname = ip.getHostName(); //获取本机名 String localip = ip.getHostAddress(); //获取本机IP地址 System.out.println("本机名:"+locaIname); //将本机名输出 System.out.println("本机名IP地址:"+localip); //将本机IP地址输出 }catch(UnknownHostException e){ e.printStackTrace(); //输出异常信息 } } }//例题21.1
- 21.2.2 ServerSocket 类
ServerSocker 类的构造方法通常会抛出1OException异常,具体有以下几种形式:
ServerSocket():创建非绑定服务器套接字。
ServerSocket(int port):创建绑定到特定端口的服务器套接字。
ServerSocket(int port, int backlog):利用指定的backlog创建服务器套接字,并将其绑定到指定的本地端口号上。
ServerSocket(int port, int backlog, InetAddress bindAddress):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器。这种情况适用于计算机上有多块网卡和多个I地址的情况,用户可以明确规定ServerSocket在哪块网卡或哪个IP地址上等待客户的连接请求。
ServerSocket 类的常用方法如表21.2所示。
-
21.2.3 TCP网络程序设计
例题
-
package 二十一章; import java.io.*; import java.net.*; public class MyServer { private ServerSocket server; // 服务器套接字 private Socket socket; // 客户端套接字 void start() {// 启动服务器 try { server = new ServerSocket(8998); // 服务器启用8998端口 System.out.println("服务器套接字已经创建成功"); while (true) { System.out.println("等待客户端的连接"); socket = server.accept(); // 服务器监听客户端连接 // 根据套接字字节流创建字符输入流 BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); while (true) {// 循环接受信息 String message = reader.readLine();// 读取一行文本 if ("exit".equals(message)) {// 如果客户端发来的内容为“exit” System.out.println("客户端退出"); break;// 停止接受信息 } System.out.println("客户端:" + message); } reader.close(); // 关闭流 socket.close(); // 关闭套接字 } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { MyServer tcp = new MyServer(); tcp.start(); // 启动服务器 } }
-
编写客户端程序,将用户在文本框中输入的信息发送至服务端,并将文本框中输入的信息显示再客户端的文本域中。
-
package 二十一章; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.Socket; import javax.swing.*; public class MyClient extends JFrame { private PrintWriter writer;// 根据套接字字节流创建的字符输出流 Socket socket; // 客户端套接字 private JTextArea area = new JTextArea();// 展示信息的文本域 private JTextField text = new JTextField(); // 发送信息的文本框 public MyClient() { setTitle("向服务器送数据"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container c = getContentPane(); // 主容器 JScrollPane scrollPane = new JScrollPane(area);// 滚动面板 getContentPane().add(scrollPane, BorderLayout.CENTER); c.add(text, "South"); // 将文本框放在窗体的下部 text.addActionListener(new ActionListener() {// 文本框触发回车事件 public void actionPerformed(ActionEvent e) { writer.println(text.getText().trim()); // 将文本框中的信息写入流 area.append(text.getText() + 'n'); // 将文本框中的信息显示在文本域中 text.setText(""); // 将文本框清空 } }); } private void connect() { // 连接服务器方法 area.append("尝试连接n"); // 文本域中提示信息 try { socket = new Socket("127.0.0.1", 8998); // 连接本地计算机的8998端口 writer = new PrintWriter(socket.getOutputStream(), true); area.append("完成连接n"); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { MyClient clien = new MyClient(); clien.setSize(200, 200); // 窗体大小 clien.setVisible(true); // 显示窗体 clien.connect(); // 连接服务器 } }
-
21.3 UDP程序
基于 UDP通信的基本模式如下:将数据打包(称为数据包),然后将数据包发往目的地。
接收别人发来的数据包,然后查看数据包。
发送数据包的步骤如下:(1)使用DatagramSocketO创建一个数据包套接字。
(2)使用DatagramPacket(byte[] buf,int offset, int length,InetAddress address,int port)创建要发送的数据包。
(3)使用DatagramSocket 类的sendO方法发送数据包。
接收数据包的步骤如下:
(1)使用DatagramSocket(int port)创建数据包套接字,绑定到指定的端口。
(2)使用 DatagramPacket(byte buf, int length)创建字节数组来接收数据包。
(3)使用DatagramPacket 类的receive0方法接收UDP包。
21.3.1 DatagramPacket类
java.net 包的DatagramPacket 类用来表示数据包。DatagramPacket 类的构造方法如下:DatagramPacket(byte[] buf, int length)
DatagramPacket(bytel] buf, int length, InetAddress address, int port)
第一种构造方法在创建DatagramPacket 对象时,指定了数据包的内存空间和大小。第二种构造方法不仅指定了数据包的内存空间和大小,还指定了数据包的目标地址和端口。
21.3.2 DatagramSocker 类
java.net 包中的()
DatagramSocket(int port)
DatagramSocket(int port, InetAddress addr)
第一种构造方法创建DatagramSocket对象,构造数据报套接字,并将其绑定到本地主机任何可用的端口上。第二种构造方法创建DatagramSocket对象,创建数据报套接字,并将其绑定到本地主机的指定端口上。第三种构造方法创建DatagramSocket对象,创建数据报套接字,并将其绑定到指定的端口和指定的本地地址上。第三种构造函数适用于有多块网卡和多个I地址的情况。21.3.3 UDP网络程序设计
例题21.3(1)广播主机程序不断地向外播放信息,代码
-
import java.io.IOException; import java.net.*; public class Notification extends Thread { String weather = "节目预报:八点有大型晚会,请收听";// 发送的消息 int port = 9898; // 端口 InetAddress iaddress = null; MulticastSocket socket = null; // 多点广播套接字 Notification() { try { iaddress = InetAddress.getByName("224.255.10.0"); // 实例化InetAddress,指定地址 socket = new MulticastSocket(port); // 实例化多点广播套接字 socket.setTimeToLive(1); // 指定发送范围是本地网络 socket.joinGroup(iaddress); // 加入广播组 } catch (IOException e) { e.printStackTrace(); // 输出异常信息 } } public void run() { while (true) { DatagramPacket packet = null; // 数据包 byte data[] = weather.getBytes(); // 字符串消息的字节数组 packet = new DatagramPacket(data, data.length, iaddress, port); // 将数据打包 System.out.println(weather); // 控制台打印消息 try { socket.send(packet); // 发送数据 sleep(3000); // 线程休眠 } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Notification w = new Notification(); w.start(); // 启动线程 } } //21.3
-
(2)接收广播程序。单机“开始接收”按钮,系统开始接收主机播出的信息;单机“停止接收”按钮,系统停止接收广播主机播出的信息。代码如下:
-
import java.awt.*; import java.awt.event.*; import java.io.IOException; import java.net.*; import javax.swing.*; public class Receive extends JFrame implements服务器托管网 Runnable, ActionListener { int port; // 端口 InetAddress group = null; // 广播组地址 MulticastSocket socket = null; // 多点广播套接字对象 JButton inceBtn = new JButton("开始接收"); JButton stopBtn = new JButton("停止接收"); JTextArea inceAr = new JTextArea(10, 10); // 显示接收广播的文本域 JTextArea inced = new JTextArea(10, 10); Thread thread; boolean stop = false; // 停止接受信息状态 public Receive() { setTitle("广播数据报"); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); thread = new Thread(this); inceBtn.addActionListener(this); // 绑定按钮ince的单击事件 stopBtn.addActionListener(this); // 绑定按钮stop的单击事件 inceAr.setForeground(Color.blue); // 指定文本域中文字的颜色 JPanel north = new JPanel(); // 创建Jpanel对象 north.add(inceBtn); // 将按钮添加到面板north上 north.add(stopBtn); add(north, BorderLayout.NORTH); // 将north放置在窗体的上部 JPanel center = new JPanel(); // 创建面板对象center center.setLayout(new GridLayout(1, 2)); // 设置面板布局 center.add(inceAr); // 将文本域添加到面板上 center.add(inced); add(center, BorderLayout.CENTER); // 设置面板布局 validate(); // 刷新 port = 9898; // 设置端口号 try { group = InetAddress.getByName("224.255.10.0"); // 指定接收地址 socket = new MulticastSocket(port); // 绑定多点广播套接字 socket.joinGroup(group); // 加入广播组 } catch (IOException e) { e.printStackTrace(); // 输出异常信息 } setBounds(100, 50, 360, 380); // 设置布局 setVisible(true); // 将窗体设置为显示状态 } public void run() { // run()方法 while (!stop) { byte data[] = new byte[1024]; // 创建缓存字节数组 DatagramPacket packet = null; packet = new DatagramPacket(data, data.length, group, port); // 待接收的数据包 try { socket.receive(packet); // 接收数据包 String message = new String(packet.getData(), 0, packet.getLength()); // 获取数据包中的内容 inceAr.setText("正在接收的内容:n" + message); // 将接收内容显示在文本域中 inced.append(message + "n"); // 每条信息为一行 } catch (IOException e) { e.printStackTrace(); // 输出异常信息 } } } public void actionPerformed(ActionEvent e) { // 单击事件 if (e.getSource() == inceBtn) { // 单击按钮ince触发的事件 inceBtn.setBackground(Color.red); // 设置按钮颜色 stopBtn.setBackground(Color.yellow); if (!(thread.isAlive())) { // 如线程不处于“新建状态” thread = new Thread(this); // 实例化Thread对象 } thread.start(); // 启动线程 stop = false; // 开始接受信息 } if (e.getSource() == stopBtn) { // 单击按钮stop触发的事件 inceBtn.setBackground(Color.yellow); // 设置按钮颜色 stopBtn.setBackground(Color.red); stop = true; // 停止接受信息 } } public static void main(String[] args) { Receive rec = new Receive(); rec.setSize(460, 200); } }
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: [Ngbatis源码学习] Ngbatis 源码阅读之资源加载器 DaoResourceLoader
Ngbatis 源码阅读之资源加载器 DaoResourceLoader DaoResourceLoader 是 Ngbatis 的资源文件加载器,扩展自 MapperResourceLoader。本篇文章主要分析这两个类。 1. 相关类 MapperReso…