Java网络通信编程学习
1. 基础网络知识概念
学习网络通信编程学习之前,先要对相关知识概念有一定了解。
**IP地址:**处于网络上的每一个设备都有一个唯一的标识(地址),这就是IP。
**端口(Port):**一个设备上可能有多个需要通信的对象(应用程序),为了在一个唯一的IP地址上找到正确的对象,需要给每个对象分配唯一的端口(0-65535,其中0-1013为系统保留)。
IP加端口(组成Socket)就可以正确的在网络上的你需要的对象了。
**协议:**找到你需要交流的对象后,这时就需要大家语言相通,否则都不知道对方在说啥了,因此需要一个语言标准,方便大家交流,这就是协议,当下用的就是随处可闻的TCP/IP协议了。
**TCP/IP协议:**
五层模型:
1.网络接口层(链路层):负责接收IP数据包并通过网络发送。
2.网络层(互联层):负责相邻计算机之间的通信,主要IP协议。
3.传输层(主机到主机层):提供应用程序间的通信,主要TCP、UDP协议。
4.应用层:向用户提供常用的应用程序,比如电子邮件、文件传输访问、远程登录等。主要协议有FTP、TELNET、DNS、SMTP、NFS、HTTP。
因为里面包含了很多网络通信协议,因此还叫__TCP/IP协议族(栈)__,用这些协议中最常用的两个协议(均处于传输层)来命名。
__TCP:Transmission Control Protocol 传输控制协议。__
__IP:Internet Protocol 互联网协议。__
2. Java的网络通信功能
Java提供了4个常用类,来针对不同的网络通信层次进行处理:
**InetAddress:**用于标识处理网络上的硬件资源,表示IP地址。
**URL:**统一资源定位符,通过它可以访问处理网络上的资源数据,由协议名称加资源名称构成,中间冒号隔开。
**Socket:**使用TCP协议实现网络通信的类。
**Datagram:**使用UDP协议,将通信内容放在数据报中,进行网络通信。
2.1 InetAddress应用
此类没有构造方法,但是提供了一些静态方法获取实例。
import java.net.*;
public class InetAddressTest{
public static void main(String[] args) throws UnknownHostException{
//获取本机的信息
InetAddress address = InetAddress.getLocalHost();
//通过主机名或者IP地址获取信息
//InetAddress address2 = InetAddress.getByName("my-pc");
InetAddress address2 = InetAddress.getByName("192.168.0.104");
System.out.println("计算机名:"+address.getHostName());
System.out.println("IP地址:"+address.getHostAddress());
System.out.println("address对象:"+address);
System.out.println("address2 计算机名:"+address2.getHostName());
System.out.println("address2 IP地址:"+address2.getHostAddress());
System.out.println("address2 address对象:"+address2);
}
}
2.2 URL应用
import java.net.*;
import java.io.*;
public class UrlDemo{
public static void main(String[] args)throws MalformedURLException,IOException {
URL baidu = new URL("http://www.baidu.com");
System.out.println("协议:"+baidu.getProtocol());
System.out.println("主机:"+baidu.getHost());
//如果没有指定,则显示-1
System.out.println("端口:"+baidu.getPort());
//字节流转换为字符流,并用缓冲类包装
InputStream is = baidu.openStream();
InputStreamReader isr = new InputStreamReader(is,"UTF-8");
BufferedReader br = new BufferedReader(isr);
//写入本地文件
FileWriter fw = new FileWriter("baidu.txt");
BufferedWriter bw = new BufferedWriter(fw);
String line = null;
while((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
}
//关闭资源
bw.close();
fw.close();
br.close();
isr.close();
is.close();
}
}
2.3 Socket应
Socket是基于TCP协议进行的。
TCP协议的特点是面向连接,可靠的,有序的,以字节流的方式发送数据。
因为通信是双方的,所以有两个相关类进行处理:客户端Socket,服务端ServerSocket。
通信流程模型:
(img)
__客户端代码:__
import java.net.*;
import java.io.*;
public class ClientDemo{
//偷懒了,直接抛出Exception了...
public static void main(String[] args) throws Exception {
//根据指定地址和端口,创建客户端socket
Socket client = new Socket("localhost",2222);
//获取输出流,发送请求
OutputStream os = client.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("你好,服务器!");
pw.flush();
//关闭输出流
client.shutdownOutput();
//获取服务端输入流
InputStream is = client.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while(null != (line = br.readLine())){
System.out.println("服务器说:"+line);
}
//关闭输入流
client.shutdownInput();
//关闭各类资源
br.close();
is.close();
pw.close();
os.close();
client.close();
}
}
__服务端代码:__
import java.net.*;
import java.io.*;
public class ServerDemo {
//偷懒了,直接抛出Exception了...
public static void main(String[] args) throws Exception{
//创建服务端的ServerSocket,绑定端口
ServerSocket serverSocket = new ServerSocket(2222);
Socket socket = null;
System.out.println("***服务器启动,等待客户端的连接***");
while(true){
//开始监听,等待客户端的连接
socket = serverSocket.accept();
//调用并执行多线程
ThreadServerDemo tsd = new ThreadServerDemo(socket);
tsd.run();
//查询监听的端口
int port = serverSocket.getLocalPort();
//查询连接的客户端IP地址
InetAddress address = socket.getInetAddress();
System.out.println("当前监听的端口:"+port);
System.out.println("当前访问的客户端IP:"+address.getHostAddress());
}
}
}
__服务端调用的多线程代码:__
import java.net.*;
import java.io.*;
public class ThreadServerDemo implements Runnable{
Socket socket = null;
public ThreadServerDemo(Socket socket){
this.socket = socket;
}
//实现Runnable接口的run方法,执行线程操作
public void run(){
//输入输出流,用于接收和返回请求
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
OutputStream os = null;
PrintWriter pw = null;
try{
//返回套接字的输入流
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String line = null;
while(null != (line = br.readLine())){
System.out.println("我是服务器,客户端说:"+line);
}
//关闭输入流
socket.shutdownInput();
//获取套接字的输出流
os = socket.getOutputStream();
pw = new PrintWriter(os);
//返回请求并刷新缓冲
pw.write("欢迎您的访问!");
pw.flush();
//关闭输出流
socket.shutdownOutput();
}catch(IOException e){
e.printStackTrace();
}finally{
try{
//关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
2.4 Datagram应用
Datagram(数据报)是基于UDP协议的。
UDP协议特点是:无连接、不可靠、无序的,传输速度快。
使用数据包进行通信时,首先需要将通信的信息定义成数据报,然后在数据报中指明需要达到的目标(主机+端口),然后再讲数据报发送出去。
需要使用到两个类:
__DatagramPacket__:表示数据报包。
__DatagramSocket__:表示用来发送和接收数据报包的套接字,进行端到端通信。
__服务端代码:__
import java.net.*;
import java.io.IOException;
public class UDPServerDemo{
public static void main(String[] args) {
try{
/*
**接收客户端发送的数据
*/
//构造绑定8888端口的套接字
DatagramSocket dataSocket = new DatagramSocket(8888);
//构造接收的数据报
byte[] content = new byte[1024];
DatagramPacket dataPacket = new DatagramPacket(content,content.length);
System.out.println("===服务器开始监听接收数据===");
//接收数据
dataSocket.receive(dataPacket);
//转换为字符串输出
String client = new String(content,0,dataPacket.getLength(),"UTF-8");
System.out.println("我是服务器,客户端说:"+client);
/*
**向客户端发送的数据
*/
//获取客户端的IP,端口
InetAddress address = dataPacket.getAddress();
int port = dataPacket.getPort();
String reContent = "你好,客户端!";
byte[] reData = reContent.getBytes();
//构造返回给客户端的数据报并发送
DatagramPacket dataPacket2 = new DatagramPacket(reData,reData.length,address,port);
dataSocket.send(dataPacket2);
//关闭套接字
dataSocket.close();
}catch(SocketException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
}
__客户端代码__
import java.net.*;
import java.io.IOException;
public class UDPClinetDemo {
public static void main(String[] args) {
String str = "服务器,你好!";
byte[] content = str.getBytes();
try{
/*
**向服务器发送数据
*/
//设置获取服务器的地址,端口
int port = 8888;
InetAddress address=InetAddress.getByName("localhost");
//构造发送的数据报,并发送数据
DatagramPacket dataPacket = new DatagramPacket(content,content.length,address,port);
DatagramSocket dataSocket = new DatagramSocket();
dataSocket.send(dataPacket);
/*
**接收服务器数据
*/
//构造接收的数据报
byte[] serverData = new byte[1024];
DatagramPacket dataPacket2 = new DatagramPacket(serverData,serverData.length);
//接收数据
dataSocket.receive(dataPacket2);
//处理接收到的数据,调用packet的getLength方法获取接收到的数据长度
String server = new String(serverData,0,dataPacket2.getLength(),"UTF-8");
System.out.println("我是客户端,服务器说:"+server);
//关闭套接字
dataSocket.close();
}catch (SocketException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
}
3 总结
1.在Socket编程中,对于同一个Socket对象,一般不需要关闭输入输出流,只要关闭Socket对象,会自动关闭对应流。
2.使用TCP传输对象时,可以使用ObjectOutputStream和ObjectInputStream进行处理。
3.使用Socket进行文件的传输时,一般是直接进行字节的读写复制。
- 点赞
- 收藏
- 关注作者
评论(0)