文章目录
提示:以下是本篇文章正文内容,Java系列学习将会持续更新
一、什么是网络编程?
网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输)。
1-1 请求和响应
一般来说,获取一个网络资源,涉及到两次网络数据传输:
- 第一次:请求数据的发送
- 第二次:响应数据的发送。
1-2 发送端和接收端
在一次网络数据传输时:
发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。
接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。
收发端:发送端和接收端两端,也简称为收发端。
1-3 客户端和服务端
- 客户端先发送请求到服务端
- 服务端根据请求数据,执行相应的业务处理
- 服务端返回响应:发送业务处理结果
- 客户端根据响应数据,展示处理结果(展示获取的资源,或提示保存资源的处理结果)
二、Socket套接字
Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程。
2-1 UDP数据报套接字
2-1-1 DatagramSocket
DatagramSocket
是UDP Socket,用于发送和接收UDP数据报。
构造方法方法说明DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)普通方法方法说明void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)void close()关闭此数据报套接字
2-1-2 DatagramPacket
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 来创建。
2-1-3 InetSocketAddress
InetSocketAddress
是
SocketAddress
的子类。
构造方法方法说明InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号
2-1-4 代码案例
服务端:
packageday1.udp.mine;importday1.udp.dictionary_service.Log;importjava.io.IOException;importjava.net.DatagramPacket;importjava.net.DatagramSocket;importjava.net.InetAddress;importjava.util.Arrays;publicclassUdpServer{// 服务器要绑定的端口privatestaticfinalint PORT =8080;publicstaticvoidmain(String[] args)throwsIOException{// 1.创建服务端DatagramSocket,指定端口,可以发送及接收UDP数据报DatagramSocket socket =newDatagramSocket(PORT);System.out.println("DEBUG: 服务器 bind 在 8080 端口上");// 2.创建数据报,用于接收客户端发送的数据byte[] buf =newbyte[1024];// 构造一个 DatagramPacket 以用来接收数据报,接收的数据保存在字节数组DatagramPacket received =newDatagramPacket(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[] + 字符集编码 -> StringString request =newString(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 =newDatagramPacket(
bytes,0, bytes.length,
address,
port
);
socket.send(sent);System.out.println("DEBUG: 响应发送成功");}}
客户端:
packageday1.udp.mine;importjava.io.IOException;importjava.net.DatagramPacket;importjava.net.DatagramSocket;importjava.net.InetAddress;importjava.util.Scanner;publicclassUdpClient{publicstaticvoidmain(String[] args)throwsIOException{Scanner input =newScanner(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 =newDatagramPacket(
bytes,0,
bytes.length,InetAddress.getLoopbackAddress(),// 得到本机地址8080);DatagramSocket socket =newDatagramSocket(9999);
socket.send(sent);System.out.println("DEBUG: 成功发送请求");System.out.println("DEBUG: 准备接收响应");byte[] buf =newbyte[1024];DatagramPacket received =newDatagramPacket(buf, buf.length);
socket.receive(received);// 服务器会阻塞int n = received.getLength();String response =newString(buf,0, n,"UTF-8");System.out.println("DEBUG: 收到响应");System.out.println(response);}}
2-2 TCP流套接字
2-2-1 ServerSocket
ServerSocket
是创建TCP服务端Socket的API。
构造方法方法说明ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口普通方法方法说明Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待void close()关闭此套接字
2-2-2 Socket
Socket
是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
构造方法方法说明Socket(String host, int port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接普通方法方法说明InetAddress getInetAddress()返回套接字所连接的地址InputStream getInputStream()返回此套接字的输入流OutputStream getOutputStream()返回此套接字的输出流
2-2-3 代码案例
服务端:
packageday2.dict_service.tcp.mine;importjava.io.*;importjava.net.ServerSocket;importjava.net.Socket;publicclassTcpServer{//服务器socket要绑定固定的端口privatestaticfinalint PORT =8888;publicstaticvoidmain(String[] args)throwsIOException{// 1.创建一个服务端ServerSocket,用于收发TCP报文ServerSocket server =newServerSocket(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 =newBufferedReader(newInputStreamReader(is,"UTF-8"));String line;// 一直读取到流结束:TCP是基于流的数据传输,一定要客户端关闭Socket输出流才表示服务端接收IO输入流结束while((line = br.readLine())!=null){System.out.println(line);}// 6.双方关闭连接:服务端是关闭客户端socket连接
client.close();}}
客户端:
packageday2.dict_service.tcp.mine;importjava.io.*;importjava.net.Socket;importjava.util.Scanner;publicclassTcpClient{//服务端IP或域名privatestaticfinalString SERVER_HOST ="localhost";//服务端Socket进程的端口号privatestaticfinalint SERVER_PORT =8888;publicstaticvoidmain(String[] args)throwsIOException{Scanner input =newScanner(System.in);// 3.创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接Socket client =newSocket(SERVER_HOST, SERVER_PORT);System.out.println("DEBUG: 建立连接。。。");// 4.发送TCP数据,是通过socket中的输出流进行发送OutputStream os = client.getOutputStream();System.out.println("DEBUG: 准备发送数据");// 为了方便输出字符串作为发送的内容,可以将以上字节流包装为字符流PrintWriter pw =newPrintWriter(newOutputStreamWriter(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协议中的不同用法。之后的学习内容将持续更新!!!
版权归原作者 一只咸鱼。。 所有, 如有侵权,请联系我们删除。