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(); } } }