网络通信必须按照一定的协议传输,目前常用的有IP协议、TCP与UDP协议,对程序员来说无非就是编程上的不同。
连接之后的数据传输,涉及到端口,套接字。
这里介绍TCP,UDP,端口\套接字,并附上一个实例
1.TCP与UDP协议
TCP协议:适合可靠性要求比较高的场合。
UDP协议:不保证可靠数据输出,但是传输速度快
2.端口、套接字
端口:一台计算机只有单一的连接到网络的物理连接,所有的数据都通过此连接对内外送达特定的计算机,这就是端口。客户端会通过不同的端口来确定连接到服务器的哪项服务上。
好比80端口一般由HTTP服务占用,21端口一般由FTP占用。
套接字:网络程序中的套接字Socket用于将应用程序与端口连接起来。
3.TCP程序设计:
服务器与客户端交互过程:
①服务器创建一个ServerSocket(服务器套接字),调用accept()方法等待客户机来连接
②客户端程序创建一个Socket,请求与服务器建立连接
③服务器接收客户机的连接请求,同时创建一个新的Socket与客户端建立连接
与IP地址相关类:
方法 | 返回值 | 说明 |
getByName(String host) | InetAddress | 获取与Host相对应的InetAddress对象 |
getHostAddress() | String | 获取InetAddress对象所含的IP地址 |
getHostName() | String | 获取此IP地址的主机名 |
getLocalHost() | InetAddress | 返回本地主机的InetAddress |
import java.net.*;
public class Address { // 创建类
public static void main(String[] args) {
InetAddress ip; // 创建InetAddress对象
try { // try语句块捕捉可能出现的异常
ip = InetAddress.getLocalHost(); // 实例化对象
String localname = ip.getHostName(); // 获取本机名
String localip = ip.getHostAddress(); // 获取本IP地址
System.out.println("本机名:" + localname);// 将本机名输出
System.out.println("本机IP地址:" + localip); // 将本机IP输出
} catch (UnknownHostException e) {
e.printStackTrace(); // 输出异常信息
}
}
}
服务器套接字类:ServerSocket类,等待来自网络上的“请求”,通过指定的端口来等待连接的套接字
ServerSocket类的常用方法:
方法 | 返回值 | 说明 |
accept() | Socket | 等待客户机的连接。若连接,则创建一套接字 |
isBound() | boolean | 判断ServerSocket的绑定状态 |
isClosed() | boolean | 返回此服务器套接字的关闭状态 |
close() | void | 关闭服务器套接字 |
bind(SocketAddress endpoint) | void | 将ServerSocket绑定到特定地址(IP地址和端口号) |
getInetAddress() | void | 将ServerSocket绑定到特定地址(IP地址和端口号) |
getInetAddress() | int | 返回服务器套接字等待端口 |
服务器端的Socket对象使用getOutputStream()方法获得的输出流将指向客户端的Socket对象使用getInputStream()方法获得的那个输入流
服务器端的Socket对象使用getOutputStream()方法获得的输入流将指向客户端的Socket对象使用getInputStream()方法获得的那个输出流
服务区代码:
package com.lzw;
import java.io.*;
import java.net.*;
public class MyTcp { // 创建类MyTcp
private BufferedReader reader; // 创建BufferedReader对象
private ServerSocket server; // 创建ServerSocket对象
private Socket socket; // 创建Socket对象socket
void getserver() {
try {
server = new ServerSocket(8998); // 实例化Socket对象
System.out.println("服务器套接字已经创建成功"); // 输出信息
while (true) { // 如果套接字是连接状态
System.out.println("等待客户机的连接"); // 输出信息
socket = server.accept(); // 实例化Socket对象
reader = new BufferedReader(new InputStreamReader(socket
.getInputStream())); // 实例化BufferedReader对象
getClientMessage(); // 调用getClientMessage()方法
}
} catch (Exception e) {
e.printStackTrace(); // 输出异常信息
}
}
private void getClientMessage() {
try {
while (true) { // 如果套接字是连接状态
if (reader.ready()) {
// 获得客户端信息
System.out.println("客户机:" + reader.readLine());
}
}
} catch (Exception e) {
e.printStackTrace(); // 输出异常信息
}
try {
if (reader != null) {
reader.close(); // 关闭流
}
if (socket != null) {
socket.close(); // 关闭套接字
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) { // 主方法
MyTcp tcp = new MyTcp(); // 创建本类对象
tcp.getserver(); // 调用方法
}
}
客户端代码:
package com.lzw;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
import javax.swing.border.*;
public class MyClien extends JFrame { // 创建类继承JFrame类
/**
*
*/
private static final long serialVersionUID = 1L;
private PrintWriter writer; // 声明PrintWriter类对象
Socket socket; // 声明Socket对象
private JTextArea ta = new JTextArea(); // 创建JtextArea对象
private JTextField tf = new JTextField(); // 创建JtextField对象
Container cc; // 声明Container对象
public MyClien(String title) { // 构造方法
super(title); // 调用父类的构造方法
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cc = this.getContentPane(); // 实例化对象
final JScrollPane scrollPane = new JScrollPane();
scrollPane.setBorder(new BevelBorder(BevelBorder.RAISED));
getContentPane().add(scrollPane, BorderLayout.CENTER);
scrollPane.setViewportView(ta);
cc.add(tf, "South"); // 将文本框放在窗体的下部
tf.addActionListener(new ActionListener() {
// 绑定事件
public void actionPerformed(ActionEvent e) {
// 将文本框中信息写入流
writer.println(tf.getText());
// 将文本框中信息显示在文本域中
ta.append(tf.getText() + '\n');
ta.setSelectionEnd(ta.getText().length());
tf.setText(""); // 将文本框清空
}
});
}
private void connect() { // 连接套接字方法
ta.append("尝试连接\n"); // 文本域中提示信息
try { // 捕捉异常
socket = new Socket("127.0.0.1", 8998); // 实例化Socket对象
writer = new PrintWriter(socket.getOutputStream(), true);
ta.append("完成连接\n"); // 文本域中提示信息
} catch (Exception e) {
e.printStackTrace(); // 输出异常信息
}
}
public static void main(String[] args) { // 主方法
MyClien clien = new MyClien("向服务器送数据"); // 创建本例对象
clien.setSize(200, 200); // 设置窗体大小
clien.setVisible(true); // 将窗体显示
clien.connect(); // 调用连接方法
}
}
4.UDP程序设计基础
UDP不是一种可靠的协议,但如果需要较快地传输信息,并能容忍小的错误,可以考虑使用UDP
①UDP程序步骤:
发送数据包
(1)使用DatagramSocket()创建一个数据包
(2)使用DatagramPacket(byte[] buf,int offset,int length,InerAddress address,int port)创建要发送的数据包
(3)使用DatagramSocket类的send()方法发送数据
接收数据包:
(1)使用DatagramSocket(int port)创建数据包套接字,绑定到指定的端口
(2)使用DatagramPacket(byte[] buf,int length)创建字节数组来接收数据包
(3)使用DatagramPacket类的receive()方法接收UDP包
DatagramPacket类表示数据包,其构造函数有:
DatagramPacket(byte[] buf,int length)指定数据包的内存空间和大小
DatagramPacket(bute[] buf,int length,InetAdress address,int port)不仅指定了数据包的内存空间和大小,还指定了数据包的目标地址和端口
DatagramSocket类表示发送和接收数据包的套接字,其构造函数有:
DatagramSocket()创建DatagramSocket对象
DatagramSocket(int port)创建DatagramSocket对象,创建数据报套接字并将其绑定在本地主机上的指定端口
DatagramSocket(int port InetAddress addr)c创建DatagramSocket对象,创建数据报套接字,并将其绑定到指定的本地地址
广播主机代码:
import java.net.*;
public class Weather extends Thread { // 创建类。该类为多线程执行程序
String weather = "节目预报:八点有大型晚会,请收听";
int port = 9898; // 定义端口
InetAddress iaddress = null; // 创建InetAddress对象
MulticastSocket socket = null; // 声明多点广播套接字
Weather() { // 构造方法
try {
// 实例化InetAddress,指定地址
iaddress = InetAddress.getByName("224.255.10.0");
socket = new MulticastSocket(port); // 实例化多点广播套接字
socket.setTimeToLive(1); // 指定发送范围是本地网络
socket.joinGroup(iaddress); // 加入广播组
} catch (Exception e) {
e.printStackTrace(); // 输出异常信息
}
}
public void run() { // run()方法
while (true) {
DatagramPacket packet = null; // 声明DatagramPacket对象
byte data[] = weather.getBytes(); // 声明字节数组
// 将数据打包
packet = new DatagramPacket(data, data.length, iaddress, port);
System.out.println(new String(data)); // 将广播信息输出
try {
socket.send(packet); // 发送数据
sleep(3000); // 线程休眠
} catch (Exception e) {
e.printStackTrace(); // 输出异常信息
}
}
}
public static void main(String[] args) { // 主方法
Weather w = new Weather(); // 创建本类对象
w.start(); // 启动线程
}
}
接收广播程序:
Aimport java.awt.*;
import java.awt.event.*;
import java.net.*;
import javax.swing.*;
public class Receive extends JFrame implements Runnable, ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
int port; // 定义int型变量
InetAddress group = null; // 声明InetAddress对象
MulticastSocket socket = null; // 创建多点广播套接字对象
JButton ince = new JButton("开始接收"); // 创建按钮对象
JButton stop = new JButton("停止接收");
JTextArea inceAr = new JTextArea(10, 10); // 显示接收广播的文本域
JTextArea inced = new JTextArea(10, 10);
Thread thread; // 创建Thread对象
boolean b = false; // 创建boolean型变量
public Receive() { // 构造方法
super("广播数据报"); // 调用父类方法
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
thread = new Thread(this);
ince.addActionListener(this); // 绑定按钮ince的单击事件
stop.addActionListener(this); // 绑定按钮stop的单击事件
inceAr.setForeground(Color.blue); // 指定文本域中文字颜色
JPanel north = new JPanel(); // 创建Jpane对象
north.add(ince); // 将按钮添加到面板north上
north.add(stop);
add(north, BorderLayout.NORTH); // 将north放置在窗体的上部
JPanel center = new JPanel(); // 创建面板对象center
center.setLayout(new GridLayout(1, 2)); // 设置面板布局
center.add(inceAr); // 将文本域添加到面板上
final JScrollPane scrollPane = new JScrollPane();
center.add(scrollPane);
scrollPane.setViewportView(inced);
add(center, BorderLayout.CENTER); // 设置面板布局
validate(); // 刷新
port = 9898; // 设置端口号
try {
group = InetAddress.getByName("224.255.10.0"); // 指定接收地址
socket = new MulticastSocket(port); // 绑定多点广播套接字
socket.joinGroup(group); // 加入广播组
} catch (Exception e) {
e.printStackTrace(); // 输出异常信息
}
setBounds(100, 50, 360, 380); // 设置布局
setVisible(true); // 将窗体设置为显示状态
}
public void run() { // run()方法
while (true) {
byte data[] = new byte[1024]; // 创建byte数组
DatagramPacket packet = null; // 创建DatagramPacket对象
// 待接收的数据包
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 (Exception e) {
e.printStackTrace(); // 输出异常信息
}
if (b == true) { // 当变量等于true时,退出循环
break;
}
}
}
public void actionPerformed(ActionEvent e) { // 单击事件
if (e.getSource() == ince) { // 单击按钮ince触发的事件
ince.setBackground(Color.red); // 设置按钮颜色
stop.setBackground(Color.yellow);
if (!(thread.isAlive())) { // 如线程不处于“新建状态”
thread = new Thread(this); // 实例化Thread对象
}
thread.start(); // 启动线程
b = false; // 设置变量值
}
if (e.getSource() == stop) { // 单击按钮stop触发的事件
ince.setBackground(Color.yellow); // 设置按钮颜色
stop.setBackground(Color.red);
b = true; // 设置变量值s
}
}
public static void main(String[] args) { // 主方法
Receive rec = new Receive(); // 创建本类对象
rec.setSize(460, 200); // 设置窗体大小
}
}