扫盲
局域网(LAN,Local Area Network):通过一定形式连接起来的计算机
广域网(WAN,Wide Area Network):LAN延伸到更大范围
因特网:由无数LAN,WAN组成
IP协议:
- (Internet Protocol)一种网络协议;
- Internet网络采用的是TCP/IP协议;
- 在Internet上存在数以亿计的主机,每台主机在网络上用为其分配的INternet地址代表自己,即IP地址;目前为止,IP地址用4个字节,即32位的二进制数来表示,称为IPv4,为便于使用,通常取每个字节的十进制数,每个字节之间用圆点隔开来表示IP地址,如192.168.1.1
- TCP/IP模式是一种层次结构,共分为4层,应用层、传输层、互联网层、网络层
- TCP/IP协议栈中,有两个高级协议,TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据报协议)
- TCP协议:以一种固定连线为基础的协议,提供两台计算机间可靠有序的数据传送,例拨打电话;HTTP、FTP、Telnet等需要使用可靠的通信频道
- UDP:无连接通信协议,不保证可靠数据的传输,但能向若干个目标发送数据,接收发自若干个源的数据;以地理发送数据包的方式进行;适用于对数据准确性要求不高的场合,如网络聊天室、在线影片等
端口:0 ~ 65535之间的整数;HTTP服务一般使用80端口,FTP服务21端口;0 ~ 1023通常用于一些知名的网络服务和应用
套接字(Socket):用于将应用程序和端口连接起来
TCP网络程序设计:用Socket类编写通信程序;利用TCP协议进行通信的两个应用程序有主次之分,一个为服务器程序,另一个为客户机程序
InetAddress类:
与IP地址相关类(会报 UnknownHostException 异常)
- getByName(String host):<InetAddress>获取与Host相对应的InetAddress对象
- getHostAddress():<String>获取InetAddress对象所包含的IP地址
- getHostName():<String>获取此IP地址的主机名 例:MR-PC
- getLocalHost():<InetAddress>返回本地主机的InetAddress对象 例:192.168.1.92
ServerSocket类
表示服务器套接字,主要用来等待来自网络上的“请求”,可通过指定端口来等待连接的套接字;服务器套接字一次可以与一个套接字连接,多台客户机同时发出请求会将请求连接的客户机存入队列中,依次取出,建立连接;队列默认大小50,超出连接请求会被拒绝(IOException 异常)
构造方法:
- ServerSocket():创建非绑定服务器的套接字
- ServerSocket(int port):创建绑定到特定端口的服务器套接字
- ServerSocket(int port,int backlog):利用指定的backlog创建服务器套接字并将其绑定到指定的本地端口号
- ServerSocket(int port, int backlog, InetAddress bindAddress):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器
常用方法:
- accept():<Socket>等待客户机连接,若连接,则创建一套接字;会返回一个和客户端Socket对象相连接的Socket对象;该方法会阻塞线程的执行,知道接收到客户的呼叫
- isBound():<boolean>判定ServerSocket的绑定状态
- getInetAddress():<InetAddress>返回此服务器套接字的本地地址
- isClosed():<boolean>返回服务器套接字的关闭状态
- close():<void>关闭服务器套接字
- bind(SocketAddress endpoint):<void>将ServerSocket绑定到特定地址(IP地址和端口号)
- getInetAddress():<int>返回服务器套接字等待的端口号
服务器端的Socket对象使用getOutputStream()方法获得的输出流将指向客户端Socket对象使用getInputStream()获得的那个输入流;同样,服务器端的Socket对象使用geInputStream()获得的输入流将指向客户端Socket对象使用getOutputStream方法获得的输出流
TCP网络程序
单向通信:客户机向服务器发送消息,不要求服务器想客户机发送消息
客户机套接字和服务器套接字连接成功后,客户机通过输出流发送数据,服务器则通过输入流接收数据
服务端关键步骤:
// 第一步:创建服务端套接字
ServerSocket server = new ServerSocket(8998);
// 第二步:等待客户机连接
Socket socket = server.accept();
// 第三步:客户机连接成功,获取客户端信息
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
reader.readLine()
// 第四步:关闭相关资源
if(reader != null) {
reader.close();
}
if(socket != null) {
socket.close();
}
可直接测试用服务端代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
/**
* TCP服务器端程序
* @author zl
*
*/
public class MyTcp {
private BufferedReader reader;
private ServerSocket server;
private Socket socket;
void getServer() {
try {
server = new ServerSocket(8998);
System.out.println("服务端套接字创建成功");
while(true) {
System.out.println("等待客户机的连接");
socket = server.accept();
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
getClientMessage();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取客户端信息
*/
private void getClientMessage() {
try {
while(true) {
System.out.println("客户机:"+reader.readLine());
}
} catch (IOException 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();
}
}
客户端主要步骤
// 第一步:连接服务端
Socket socket = new Socket("127.0.0.1", 8998);
// 第二步:将客户端信息写入流中
PrintWriter writer = new PrintWriter(socket.getOutputStream(),true);
writer.println(text);
可测试用客户端代码
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;
/**
* 客户端程序
* 用户在文本框中输入信息发给服务器
* @author zl
*
*/
public class MyClien extends JFrame {
private PrintWriter writer;
Socket socket;
private JTextArea ta = new JTextArea();
private JTextField tf = new JTextField();
Container cc;
public MyClien(String title) {
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cc = this.getContentPane();
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() {
@Override
public void actionPerformed(ActionEvent e) {
writer.println(tf.getText());
ta.append(tf.getText()+'\n');
ta.setSelectionEnd(ta.getText().length());
tf.setText("");
}
});
}
public void connect() {
ta.append("尝试连接\n");
try {
socket = new Socket("127.0.0.1", 8998);
writer = new PrintWriter(socket.getOutputStream(),true);
ta.append("完成连接\n");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
MyClien clien = new MyClien("向服务器送数据");
clien.setSize(200,200);
clien.setVisible(true);
clien.connect();
}
}
UDP
用户数据报协议(udp):网络信息传输的另一种形式;比TCP:更快,不可靠
DatagramPacket:表示数据包
DatagramSocket:表示发送和接收数据包的套接字
模式:
- 将数据打包(数据包),然后将数据包发往目的地
- 接收别人发来的数据包,然后查看数据包
使用步骤:
发送
- 使用DatagramSocket()创建一个数据报套接字
- 使用DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 创建要发送的数据包 《四个参数:数据包的内存空间和大小,数据包的目标地址和端口》;在发送时必须指定接收方Socket地址和端口号
- 使用 DatagramSocket类的send()方法发送数据包
接收
- 使用DatagramSocket(int port) 创建数据包套接字,绑定到指定的端口;在接收程序的时候,必须指定一个端口号
- 使用DatagramPacket(byte[] buf, int length)创建字节数组来接收数据包《两个参数:数据包的内存空间和大小》
- 使用DatagramPacket类的receive()接收UDP包,在没有可接收的数据时,会阻塞,等到数据传来
示例:广播数据报程序
主机不断地重复播出节目预报,保证加入到同一组的主机随时可以接收到广播信息。接受者将正在接收的信息放在一个文本域中,并将接收的全部信息放在另一个文本域中
地址范围:224.0.0.0~224.255.255.255
主机代码:
主要代码:
// 一、创建一个数据包套接字
MulticastSocket socket = new MulticastSocket(9898);
// 二、创建要发送的数据包
InetAddress iaddress = InetAddress.getByName("224.255.1.0");
byte data[] = weather.getBytes(); // 声明字节数组
DatagramPacket packet = new DatagramPacket(data, data.length,iaddress,port);
// 三、发送数据
socket.send(packet);
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
public class Weather extends Thread{
String weather = "节目预报:八点有大型晚会,请收听";
int port = 9898;
InetAddress iaddress = null;
MulticastSocket socket = null;// 声明多点广播套接字
// 构造方法
Weather() {
try {
iaddress = InetAddress.getByName("224.255.1.0");
socket = new MulticastSocket(port);
socket.setTimeToLive(1);// 指定发送范围是本地网络
socket.joinGroup(iaddress); // 加入广播组
} catch (UnknownHostException e) {
e.printStackTrace();
} 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(new String(data));
try {
// 发送数据
socket.send(packet);
sleep(3000);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Weather w = new Weather();
w.start();
}
}
接收广播程序:
主要代码
// 第一步:绑定多点广播套接字
MulticastSocket socket = new MulticastSocket(9898);
// 第二步:接收数据包
InetAddress group = InetAddress.getByName("224.255.1.0");
byte data[] = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length,group,9898);
// 第三步:接收UDP包
socket.receive(packet);
String message = new String(packet.getData(),0,packet.getLength());
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;
public class Receive extends JFrame implements Runnable,ActionListener{
int port;
InetAddress group = null;
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;
boolean b = false;
public Receive() {
super("广播数据报");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
thread = new Thread(this);
ince.addActionListener(this); // 绑定单击事件
stop.addActionListener(this);
inceAr.setForeground(Color.blue);
JPanel north = new JPanel();
north.add(ince);
north.add(stop);
add(north,BorderLayout.NORTH);
JPanel center = new JPanel();
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.1.0");
// 绑定多点广播套接字
socket = new MulticastSocket(port);
// 加入广播组
socket.joinGroup(group);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
setBounds(100,50,360,380);
setVisible(true);
}
// 单击事件
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == ince) {
ince.setBackground(Color.RED);
stop.setBackground(Color.yellow);
if(!(thread.isAlive())) {
thread = new Thread(this);
}
thread.start();
b = false;
}
if(e.getSource() == stop) {
ince.setBackground(Color.yellow);
stop.setBackground(Color.red);
b = true;
}
}
public static void main(String[] args) {
Receive rec = new Receive();
rec.setSize(460,200);
}
@Override
public void run() {
while(true) {
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();
}
if(b == true) {
break;
}
}
}
}