OSI模型分为七层(从下到上):物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
不同主机之间的相同层次称为对等层。对等层之间互相通信需要遵守一定的规则,称之为协议,我们将某个主机上运行的某种协议的集合称为协议栈。主机正是利用这个协议栈来接收和发送数据的。
TCP/IP模型:网络接口层、网络互连层、传输层、应用层。
在网络编程中需要注意的问题包括:
1.是如何找到网络上的主机上的要进行通讯的程序;
2.是找到了主机上的程序后如何传输数据。
端口号:是一组16位的无符号二进制数,每个端口号的范围是1到65535(0被保留)。
TCP协议代表传输控制协议,允许两个应用程序之间的进行可靠的通讯;
UDP协议代表用户报文协议,是一种非连接协议,允许两个应用程序之间进行不可靠的通讯。提供了在应用程序之间发送称为数据报的协议。
Socket套接字:Unix系统推出了一种应用程序访问通信协议的操作系统调用,是一种抽象层,应用程序通过它来发送和接收数据。
不同类型的Socket与不同类型的底层协议族以及同一协议族中的不同协议栈相关联。
InetAddress类代表IP地址,例:
import java.net.InetAddress;
public class InetAddressTest {
public static void main(String[] args) throws Exception {
InetAddress ip = InetAddress.getLocalHost();
System.out.println(ip);
InetAddress ip = InetAddress.getByName("80YMEKCC96RXAOB");
System.out.println(ip);
InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
for (InetAddress inetAddress : allByName) {
System.out.println(inetAddress);
}
byte[] ip = {(byte)192, (byte)168, 1, 52};
InetAddress address = InetAddress.getByAddress("www.baidu.com", ip);
System.out.println(address);
}
}
使用套接字建立TCP连接:
1.服务器初始化一个ServerSocket对象,指示通讯将要发生在哪个端口号上。
2.服务器调用ServerSocket类的accept()方法。该方法会一直等待,直到一个客户端连接到服务器上的指定端口。
3.在服务器等待的同时,客户端实例化一个Socket对象,指定要连接的服务器名和端口号。
4.Socket类的构造器试图将客户端连接到指定的服务器和端口号。
5.在服务器端,accept()方法返回一个将要连接到客户端套接字的服务器新套接字的引用。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务器端
*
* @author Administrator
*
*/
public class Server {
public static void main(String[] args) throws IOException {
// 创建ServerSocket对象,指定监听端口
ServerSocket server = new ServerSocket(30001);
// 设置超时时间
server.setSoTimeout(10000);
// 等待客户端连接
Socket socket = server.accept();
/* 处理客户端数据 */
// 从客户端读数据
BufferedReader reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
char[] ch = new char[100];
int len = reader.read(ch);
System.out.println("从客户端接收到的信息:");
// while (-1 != (len = reader.read(ch))) {
System.out.print(new String(ch, 0, len));
// }
// 向客户端写数据
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));
writer.write("你好客户端,我已经接收到你的信息了");
writer.flush();
// 释放资源
writer.close();
reader.close();
socket.close();
server.close();
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
/**
* 客户端 请求--响应
*
* @author Administrator
*
*/
public class Client {
public static void main(String[] args) throws IOException {
// 创建客户端Socket向服务器发起连接请求
Socket socket = new Socket("192.168.1.200", 30001);
/* 利用已建立的socket创建输入输出流,处理与服务器端的连接 */
// 向服务器写入数据
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));
writer.write("你好服务器!!!");
writer.flush();
// 从服务器读数据
BufferedReader reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
char[] ch = new char[100];
int len = reader.read(ch);
System.out.println("从服务器端接收到的信息:");
// while (-1 != (len = reader.read(ch))) {
System.out.print(new String(ch, 0, len));
// }
// 释放资源
reader.close();
writer.close();
socket.close();
}
}
UDP套接字编程
数据报包的发送者和接受者都使用java.net.DatagramSocket类分别发送和接收包。
接收报文包:
1.创建一个足够大的字节数组,用于存储要接收的包的数据;
2.使用该字节数组实例化一个DatagramPacket对象;
3.DatagramSocket被实例化,它被指定该套接字要绑定到的本地主机上的一个端口;
4.调用DatagramSocket类的receive()方法,将DatagramPacket对象传入该方法。这将导致执行线程阻塞,直到接收到一个数据报包或者发生了超时。
import java.net.*;
import java.io.*;
public class PacketReceiver{
public static void main(String[] args) {
try{
byte[] buffer = new byte [1024];
DatagramOacket packet = new DatagramPacket(buffer,buffer.length);
DatagramSocket socket = new DatagramSocket(5002);
Syatem.out.println("正在等待一个包...");
socket.receive(packet);
System.out.println("刚从" + packet.getSocketAddress() + "接收到包");
buffer = packet.getData();
System.out.println("new String(buffer)");
} catch(IOException e){
e.printStackTrace();
}
}
}
发送报文包
1.创建一个足够大的字节数组,用于存储要发送的包数据,用该数据填充数组;
2.创建一个新的DatagramPacket对象,用于存储上面的字节数组,以及服务器名和接受者的端口号;
3.DatagramSocket被实例化,它被指定套接字要绑定到本地主机的哪个端口;
4.DatagramSocket类的send()方法被调用,传入DatagramPacket对象。
import java.net.*;
import java.io.*;
public class PacketSender{
public static void main(String [] args){
try{
String data = "刚收到数据包";
byte[] buffer = data.getBytes();
DatagramPacket packet = new DatagramPacket(buffer,buffer.length,new InetSocketAddress("localhost",5002));
DatagramSocket socket = new DatagramSocket(5003);
System.out.println("正在发送一个包...");
Socket.send(packet);
} catch(IOException e){
e.printStackTrace();
}
}
}