Java作业六 网络通信
1. 什么是TCP/IP协议?它有什么特点?
答:
(1)什么是TCP/IP协议
TCP/IP传输协议,即传输控制/网络协议,也叫作网络通讯协议。它是在网络的使用中的最基本的通信协议。TCP/IP传输协议对互联网中各部分进行通信的标准和方法进行了规定。并且,TCP/IP传输协议是保证网络数据信息及时、完整传输的两个重要的协议。TCP/IP传输协议是严格来说是一个四层的体系结构,应用层、传输层、网络层和数据链路层都包含其中,其中应用层的主要协议有Telnet、FTP、SMTP等,是用来接收来自传输层的数据或者按不同应用要求与方式将数据传输至传输层;传输层的主要协议有UDP、TCP,是使用者使用平台和计算机信息网内部数据结合的通道,可以实现数据传输与数据共享;网络层的主要协议有ICMP、IP、IGMP,主要负责网络中数据包的传送等;而网络访问层,也叫网路接口层或数据链路层,主要协议有ARP、RARP,主要功能是提供链路管理错误检测、对不同通信媒介有关信息细节问题进行有效处理等。
(2)TCP/IP协议特点
协议标准是完全开放的,并且独立于特定的计算机硬件与操作系统;
独立于网络硬件系统,可以运行在广域网,更适合于互联网;
网络地址统一分配,网络中每一设备和终端都具有一个唯一地址;
高层协议标准化,可以提供多种多样可靠网络服务。
2.简述URL与Socket通信的区别。
答:
(1)区别
Socket:
利用socket进行通信时,在服务器端运行一个socket通信程序。服务器端不停地监听某个端口,等待客户的连接申请,接到申请后建立连接并进行通信,所以,在socket通信方式中,服务器是主动等待连接通信的到来。
利用socket进行通信时,服务器端的程序可以打开多个线程与多个客户进行通信,还可以通过服务器使各个客户之间进行通信。这种方式比较灵活,适用于一些较复杂的通信,但是服务器端的程序必须始终处于运行状态以监听端口。
URL:
利用URL进行通信时,在服务器端常驻一个CGI程序,但它一直处于休眠状态。只有在客户端要求建立连接时才被激活,然后与用户进行通信。所以,在URL 通信方式中,服务器是被动等待连接通信的到来。
利用 URL进行通信时,服务器端的程序只能与一个客户进行通信,形式比较单一。但是它不需要服务器端的CGI程序一直处于运行状态,只是在有客户申请时才被激活。所以,这种方式比较适用于客户机的浏览器与服务器之间的通信。
3.简述Socket通信机制,说明客户端如何与服务器进行连接。
答:
(1)通信机制
Server端创建ServerSocket对象,监听某端口;Client端创建Socket对象,向Server的监听服务发送连接请求;
Server端接受Client端的请求,用accept()返回的Socket建立连接,此时连接建立。Server端和Client端分别通过向Socket读写数据完成与对方的通信,这称作数据通信。最后是拆分连接,Client端关闭Socket,结束Server端的通信,Server端关闭Socket,结束与当前Client的通信,等待其它请求。如果没有其他请求,Server端关闭ServerSocket对象,结束监听服务。
(2)客户端和服务器连接
服务器端生成一个ServerSocket实例对象,随时监听客户端的连接请求;客户端生成一个Socket实例对象,并发出连接请求;服务器端通过accept()方法接收到客户端的请求后,开辟一个接口与之进行连接,并生成所需的I/O数据流;通信都是通过一对InputStream()和OutputStream()进行的,通信结束后,两端分别关闭对应的Socket接口。
4.说明并尝试通过URL从服务器上读取一个文本文件,并显示该文本文件的内容。
/**
* FileName: HomeWork6_4
* Author: zhangnuanxin
* Date: 2020/10/21 06:00
* Description:
* 说明并尝试通过URL从服务器上读取一个文本文件,并显示该文本文件的内容。
* History:
* <author> <time> <version> <desc>
* zhangnuanxin 2020/10/21 1.0 描述
*/
import java.net.*;
import java.io.*;
public class HomeWork6_4
{
public static void main(String args[]) throws Exception //直接抛出异常,不做处理
{
URL myurl = new URL("https://mirrors6.tuna.tsinghua.edu.cn/ubuntu-releases/robots.txt");
/*
* 创建URL对象
* 采用的地址为清华大学tuna开源镜像站
* 访问方式为ipv6,速度快,连接稳定
* txt内容为:User-Agent: *
* Disallow: .pool
* Disallow: /*(和左边一样的斜杠).pool
*/
URLConnection uc = myurl.openConnection();
//创建连接
InputStreamReader isr = new InputStreamReader(uc.getInputStream());
//获取服务器端字节流
BufferedReader in = new BufferedReader(isr);
//读取服务器端文件
String inputLine;
//按行读取文件
while ((inputLine = in.readLine()) != null)
{
System.out.println(inputLine);
}
//当读取行不为空时按行输出读取内容
in.close();
//关闭
}
}
5.编写程序,用Socket通信机制在服务器和客户端之间传输文件。
服务器端
/**
* FileName: HomeWork6_5Server
* Author: zhangnuanxin
* Date: 2020/10/21 16:00
* Description:
* 编写程序,用Socket通信机制在服务器和客户端之间传输文件
* History:
* <author> <time> <version> <desc>
* zhangnuanxin 2020/10/21 1.0 描述
*/
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.math.RoundingMode;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.DecimalFormat;
public class HomeWork6_5Server extends ServerSocket
{
private static final int SERVER_PORT = 8888; // 服务端端口
private static DecimalFormat df = null;
static
{
// 设置数字格式,保留一位有效小数
df = new DecimalFormat("#0.0");
df.setRoundingMode(RoundingMode.HALF_UP);
df.setMinimumFractionDigits(1);
df.setMaximumFractionDigits(1);
}
public HomeWork6_5Server() throws Exception
{
super(SERVER_PORT);
}
//使用线程处理每个客户端传输的文件
public void load() throws Exception
{
while (true)
{
// server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的
Socket socket = this.accept();
/*
* 采用如下这种异步处理与客户端通信的方式,避免在并发比较多的情况下严重影响程序的性能
*/
new Thread(new Task(socket)).start();
// 每接收到一个Socket就建立一个新的线程来处理它
}
}
/**
* 处理客户端传输过来的文件线程类
*/
class Task implements Runnable
{
private Socket socket;
private DataInputStream dis;
private FileOutputStream fos;
public Task(Socket socket)
{
this.socket = socket;
}
@Override
public void run()
{
try {
dis = new DataInputStream(socket.getInputStream());
// 文件名和长度
String fileName = dis.readUTF();
long fileLength = dis.readLong();
File directory = new File("D:\\FTCache");
if(!directory.exists()) {
directory.mkdir();
}
File file = new File(directory.getAbsolutePath() + File.separatorChar + fileName);
fos = new FileOutputStream(file);
// 开始接收文件
byte[] bytes = new byte[1024];
int length = 0;
while((length = dis.read(bytes, 0, bytes.length)) != -1) {
fos.write(bytes, 0, length);
fos.flush();
}
System.out.println("======== 文件接收成功 [File Name:" + fileName + "] [Size:" + getFormatFileSize(fileLength) + "] ========");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(fos != null)
fos.close();
if(dis != null)
dis.close();
socket.close();
} catch (Exception e) {}
}
}
}
/**
* 格式化文件大小
* @param length
* @return
*/
private String getFormatFileSize(long length) {
double size = ((double) length) / (1 << 30);
if(size >= 1) {
return df.format(size) + "GB";
}
size = ((double) length) / (1 << 20);
if(size >= 1) {
return df.format(size) + "MB";
}
size = ((double) length) / (1 << 10);
if(size >= 1) {
return df.format(size) + "KB";
}
return length + "B";
}
public static void main(String[] args) {
try {
HomeWork6_5Server server = new HomeWork6_5Server(); // 启动服务端
server.load();
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端
/**
* FileName: HomeWork6_5Client
* Author: zhangnuanxin
* Date: 2020/10/21 16:00
* Description:
* 编写程序,用Socket通信机制在服务器和客户端之间传输文件
* History:
* <author> <time> <version> <desc>
* zhangnuanxin 2020/10/21 1.0 描述
*/
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.Socket;
import com.sun.tools.javac.Main;
public class HomeWork6_5Client extends Socket
{
private static final String SERVER_IP = "127.0.0.1"; // 服务端IP
private static final int SERVER_PORT = 8888; // 服务端端口
private Socket client;
private FileInputStream fis;
private DataOutputStream dos;
//与服务器建立连接
public HomeWork6_5Client() throws Exception
{
super(SERVER_IP, SERVER_PORT);
this.client = this;
System.out.println("Cliect[port:" + client.getLocalPort() + "] 成功连接服务端");
}
//向服务器传输文件
public void sendFile() throws Exception
{
try
{
File file = new File("C:\\test.txt");
if(file.exists()) {
fis = new FileInputStream(file);
dos = new DataOutputStream(client.getOutputStream());
// 文件名和长度
dos.writeUTF(file.getName());
dos.flush();
dos.writeLong(file.length());
dos.flush();
// 开始传输文件
System.out.println("======== 开始传输文件 ========");
byte[] bytes = new byte[1024];
int length = 0;
long progress = 0;
while((length = fis.read(bytes, 0, bytes.length)) != -1)
{
dos.write(bytes, 0, length);
dos.flush();
progress += length;
System.out.print("| " + (100*progress/file.length()) + "% |");
}
System.out.println();
System.out.println("======== 文件传输成功 ========");
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
if(fis != null)
fis.close();
if(dos != null)
dos.close();
client.close();
}
}
public static void main(String[] args)
{
try
{
HomeWork6_5Client client = new HomeWork6_5Client(); // 启动客户端连接
client.sendFile(); // 传输文件
}
catch (Exception e)
{
e.printStackTrace();
}
}
}