赞
踩
网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输)。
一般来说,获取一个网络资源,涉及到两次网络数据传输:
在一次网络数据传输时:
发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。
接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。
收发端:发送端和接收端两端,也简称为收发端。
Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程。
DatagramSocket
是UDP Socket,用于发送和接收UDP数据报。
构造方法 | 方法说明 |
---|---|
DatagramSocket() | 创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端) |
DatagramSocket(int port) | 创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端) |
普通方法 | 方法说明 |
---|---|
void receive(DatagramPacket p) | 从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待) |
void send(DatagramPacket p) | 从此套接字发送数据报包(不会阻塞等待,直接发送) |
void close() | 关闭此数据报套接字 |
DatagramPacket
是UDP Socket发送和接收的数据报。
构造方法 | 方法说明 |
---|---|
DatagramPacket(byte[] buf, int length) | 构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length) |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) | 构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号 |
普通方法 | 方法说明 |
---|---|
InetAddress getAddress() | 从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址 |
int getPort() | 从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号 |
byte[] getData() | 获取数据报中的数据 |
构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。
InetSocketAddress
是 SocketAddress
的子类。
构造方法 | 方法说明 |
---|---|
InetSocketAddress(InetAddress addr, int port) | 创建一个Socket地址,包含IP地址和端口号 |
服务端:
package day1.udp.mine; import day1.udp.dictionary_service.Log; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Arrays; public class UdpServer { // 服务器要绑定的端口 private static final int PORT = 8080; public static void main(String[] args) throws IOException { // 1.创建服务端DatagramSocket,指定端口,可以发送及接收UDP数据报 DatagramSocket socket = new DatagramSocket(PORT); System.out.println("DEBUG: 服务器 bind 在 8080 端口上"); // 2.创建数据报,用于接收客户端发送的数据 byte[] buf = new byte[1024]; // 构造一个 DatagramPacket 以用来接收数据报,接收的数据保存在字节数组 DatagramPacket received = new DatagramPacket(buf, buf.length); System.out.println("DEBUG: 服务器准备接收数据"); // 3.等待接收客户端发送的UDP数据报,该方法在接收到数据报之前会一直阻塞 socket.receive(received); System.out.println("DEBUG: 服务器接收到了数据"); // 对方的地址(ip) InetAddress address = received.getAddress(); System.out.println("DEBUG: 对方的地址为: " + address); // 对方的端口(port) int port = received.getPort(); System.out.println("DEBUG: 对方的端口为: " + port); // 真正收到的数据长度 int n = received.getLength(); System.out.println("DEBUG: 数据长度为: " + n); // 真正有用的数据 byte[] actualData = Arrays.copyOf(buf, n); // byte[] + 字符集编码 -> String String request = new String(actualData, 0, actualData.length, "UTF-8"); System.out.println("DEBUG: 解析到的请求为: " + request); // 处理请求 System.out.println("DEBUG: 开始处理请求数据"); String response = "我们已经对 " + request + " 请求,作出了响应。"; // String + 字符集编码 -> byte[] byte[] bytes = response.getBytes("UTF-8"); System.out.println("DEBUG: 数据处理完毕"); // 发送响应 System.out.println("DEBUG: 准备发送响应"); DatagramPacket sent = new DatagramPacket( bytes, 0, bytes.length, address, port ); socket.send(sent); System.out.println("DEBUG: 响应发送成功"); } }
客户端:
package day1.udp.mine; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Scanner; public class UdpClient { public static void main(String[] args) throws IOException { Scanner input = new Scanner(System.in); System.out.println("DEBUG: 请输入请求数据"); String request = input.nextLine(); System.out.println("DEBUG: 将请求数据打包"); byte[] bytes = request.getBytes("UTF-8"); System.out.println("DEBUG: 准备发送请求"); DatagramPacket sent = new DatagramPacket( bytes, 0, bytes.length, InetAddress.getLoopbackAddress(), // 得到本机地址 8080 ); DatagramSocket socket = new DatagramSocket(9999); socket.send(sent); System.out.println("DEBUG: 成功发送请求"); System.out.println("DEBUG: 准备接收响应"); byte[] buf = new byte[1024]; DatagramPacket received = new DatagramPacket(buf, buf.length); socket.receive(received); // 服务器会阻塞 int n = received.getLength(); String response = new String(buf, 0, n, "UTF-8"); System.out.println("DEBUG: 收到响应"); System.out.println(response); } }
ServerSocket
是创建TCP服务端Socket的API。
构造方法 | 方法说明 |
---|---|
ServerSocket(int port) | 创建一个服务端流套接字Socket,并绑定到指定端口 |
普通方法 | 方法说明 |
---|---|
Socket accept() | 开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待 |
void close() | 关闭此套接字 |
Socket
是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
构造方法 | 方法说明 |
---|---|
Socket(String host, int port) | 创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接 |
普通方法 | 方法说明 |
---|---|
InetAddress getInetAddress() | 返回套接字所连接的地址 |
InputStream getInputStream() | 返回此套接字的输入流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
服务端:
package day2.dict_service.tcp.mine; import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class TcpServer { //服务器socket要绑定固定的端口 private static final int PORT = 8888; public static void main(String[] args) throws IOException { // 1.创建一个服务端ServerSocket,用于收发TCP报文 ServerSocket server = new ServerSocket(PORT); System.out.println("DEBUG: 服务器 bind 在 8080 端口上"); // 2.等待客户端连接,注意该方法为阻塞方法 System.out.println("DEBUG: 等待客户端建立TCP连接..."); Socket client = server.accept(); System.out.println("DEBUG: 连接成功"); System.out.printf("DEBUG: 客户端IP:%s%n", client.getInetAddress().getHostAddress()); System.out.printf("DEBUG: 客户端端口号:%s%n", client.getPort()); // 5.接收客户端的数据,需要从客户端Socket中的输入流获取 System.out.println("接收到客户端请求:"); InputStream is = client.getInputStream(); // 为了方便获取字符串内容,可以将以上字节流包装为字符流 BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); String line; // 一直读取到流结束:TCP是基于流的数据传输,一定要客户端关闭Socket输出流才表示服务端接收IO输入流结束 while ((line = br.readLine()) != null) { System.out.println(line); } // 6.双方关闭连接:服务端是关闭客户端socket连接 client.close(); } }
客户端:
package day2.dict_service.tcp.mine; import java.io.*; import java.net.Socket; import java.util.Scanner; public class TcpClient { //服务端IP或域名 private static final String SERVER_HOST = "localhost"; //服务端Socket进程的端口号 private static final int SERVER_PORT = 8888; public static void main(String[] args) throws IOException { Scanner input = new Scanner(System.in); // 3.创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接 Socket client = new Socket(SERVER_HOST, SERVER_PORT); System.out.println("DEBUG: 建立连接。。。"); // 4.发送TCP数据,是通过socket中的输出流进行发送 OutputStream os = client.getOutputStream(); System.out.println("DEBUG: 准备发送数据"); // 为了方便输出字符串作为发送的内容,可以将以上字节流包装为字符流 PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "UTF-8")); // 4-1.发送数据: System.out.println("DEBUG: 请发送数据"); pw.println(input.nextLine()); // 4-2.有缓冲区的IO操作,真正传输数据,需要刷新缓冲区 pw.flush(); // 7.双方关闭连接:客户端关闭socket连接 client.close(); System.out.println("DEBUG: 关闭连接"); } }
总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,本文是Java网络编程的学习,学习如何进行网络编程,Socket套接字在UDP和TCP协议中的不同用法。之后的学习内容将持续更新!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。