Java网络编程
internet互联网 指最大范围的互联网
Internet因特网 属于互联网的子网
WWW万维网 也属于互联网中的子网,最小
应用层 HTTP网页/FTP文件传输/SMTP邮件/DNS域名解析
显示层
会话层 以上3层都是软件相关
传输层 TCP/UDP
网络层 Internet协议
数据链路层 路由器
物理层 硬件设备:同轴电缆,光纤,交换机
IP地址和端口号
服务器IP地址只能有一个,端口号可以有多个,端口号是一台服务器上部署的多个应用程序的识别码。应用程序和端口号绑定。端口如果被占用也可以换绑。
TCP、UDP协议
TCP(Transmission Control Protocol)传输控制协议
UDP(User Datagram Protocol)用户数据报协议
TCP传输协议是面向连接的,传输数据是最为安全的,确保数据一定会发送到目标位置,但是速度较慢;
UDP是面向断开式连接的通信协议,不确保数据一定会发送到目标位置,但是速度较快
java.net组件包
java.net.URL 统一资源定位符
java.net.Address 互联网IP地址
java.net.Socket 客户端套接字
java.net.ServerSocket 服务器端套接字
java.net.DatagramPacket 数据报包
java.net.DatagramSocket 数据报包套接字
URL
URL类代表一个统一资源定位符,指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,如对数据库或搜索引擎的查询、更改等操作。
例:http://www.baidu.com/index.jsp
http是传输协议,http是tcp的一种,叫超文本传输协议。baidu是域名,会映射实际的ip地址。index.jsp是请求的资源名称
URL构造器
public URL(String spec) throws MalformedURLException
//spec是一个URL的字符串描述,构建一个URL
public URL(String protocol,String host,int port,String file) throws MalformedURLException
//String protoco表示给一个协,String host表示ip地址或机器名称,String file表示文件名
public URL(String protocol,String host,int port,String file) throws MalformedURLException
//比上面的多了一个int port表示端口号,没有这个参数则表示默认端口号
public URL(URL context,String spec) throws MalformedURLException
//URL context连接后面的一个String spec名称作为相对路径
InetAddress/SocketAddress
此类表示互联网协议(IP)地址
IP地址是IP使用的32位或128位无符号数字,它是一种低级协议,UDP和TCP协议都是在它的基础上构建的
Inet4Address InetAddress分别是IPv4和IPv6,是InetAddress直接子类
InetSocketAddress是SocketAddress直接子类
Socket
Socket类实现客户端套接字(简称“套接字”)。套接字是两台机器间通信的端点。
java基于互联网的C/S模式的客户端程序主要依赖此类实现与服务器端的通信,它是java网络编程的核心组件。
Socket组件实例通常必须绑定IP地址(客户机网络域名)和一个未被在本地机器占用的端口号
public Socket() 创建未连接的套接字
public Socket(InetAddress address,int port) 创建指定IP地址和端口号的套接字
public Socket(InetAddress address,int port,InetAddress localAddr,int localFort) 创建连接到远处服务器的套接字
public Socket(String host,int port) 创建一个流套接字并将其连接到指定主机上的指定端口号
void bind(SocketAddress bindpoint) 将套接字绑定到本地地址
void close() 关闭此套接字
void connect(SocketAddress endpoint) 将此套接字连接到服务器
void connect(SocketAddress endpoint,int timeout) 指定超时时间
InputStream getInputStream() 返回此套接字的输入流
OnputStream getOutputStream() 返回此套接字的输出流
ServerSocket
ServerSocket类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。
public ServerSocket() throws IOException 创建非绑定服务器套接字
public ServerSocket(int port) 创建绑定到特定端口的服务器套接字
public ServerSocket(int port,int backlog) 指定端口号和队列长度
public ServerSocket(int port,int backlog,InetAddress bindAddr) 指定端口号队列长度及指定主机地址创建套接字
public Socket accept() throws IOException 侦听并接收到此套接字的连接,未连接前处于阻塞状态
void close() 关闭此套接字
public void setSoTimeout(int timeout)以毫秒为单位设置超时时间如果为0则永不超时
public boolean isBound() 测试ServerSocket是否绑定
public boolean isClosed() 测试ServerSocket是否关闭
public InetAddress getInetAddress() 返回此服务器套接字的本地地址
DatagramPacket类表示用户数据报包
- 数据报包用来实现无连接包投递服务。数据报包中可以包含各种类型的数据对象。
- 每条报文只根据该包中包含的信息(通常是url和端口号)从一台机器路由到另一台机器。
- 从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证
public DatagramPacket(bytep[] buf,int len) 构建用来接收长度为length的数据包,len必须小于等于buf长度
public DatagramPacket(byte[] buf,int len,SocketAddress add) 构建用来接收长度为length的数据包,指定发送目的地址
public DatagramPacket(byte[] buf,int len,InetAddress add,int port) 构建用来接收长度为length的数据包,指定发送目的地址和端口号
public void setData(bytep[] buf) 设置数据缓冲区
public void setSocketAddress(SocketAddress address)
public void setLength(int length) 设置数据包缓冲区长度
public byte[] getData() 获取数据包缓冲区
public int getLength() 返回将要发送或者接收到的数据的长度
DatagramSocket类表示用来发送和接收数据包的套接字。
数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。
public DatagramSocket()throws SocketException 构造数据报套接字并将其绑定到本地主机上任何可用的端口
public DatagramSocket 创建数据报套接字并将其绑定到本地主机上的指定端口
public DatagramSocket 创建数据报套接字,将其绑定到指定的本地地址
public DatagramSocket 创建数据报套接字,将其绑定到指定的本地套接字地址
public void bind(SocketAddress addr) throws SocketException 绑定端口号到主机地址上
public void connect(SocketAddress add) throws SocketException 连接要发送的目的地
public void disconnect() 断开套接字连接
public void receive(DatagramPacket p) 接收数据包
public void send(DatagramPacket p) 发送数据包
public void close() 关闭数据包套接字
/** * 1使用Eclipse 集成开发工具建立一个服务器端控制台应用程序,此程序能够等待并接收N个客户端的连接, * 并在与客户端连接成功后,向客户端发送连接成功的消息(如: 连接成功,可以上传文件)。 * 服务器端在接收到客户端上传的文件后能够将文件保存到服务器端系统某硬盘位置, 并应考虑上传文件不 * 能与已经存在的文件重名. 在文件上传成功或失败时应能向客户端发送相应的信息。在客户端断开连接后 * 应能够将客户端对象在服务器内存中释放。 * * 2使用Eclipse 集成开发工具建立一个客户端控制台应用程序, 此程序在启动运行后应能够实现与上述 * 服务器端应用程序进行连接,在服务器返回连接成功后可以实现将用户选择的客户端机器上的文件上传到 * 服务器。文件上传成功或失败应能够接收到服务器返回的信息,并且可以再次选择上传新文件及选择与服 * 务器端断开连接并退出系统,退出系统时应给出提示,在用户确认后退出. */ package until; import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { ServerSocket serverSocket = null; //实例化一个为null的服务器套接字,不能直接new Socket client = null; //实例化一个为null的客户端套接字 InputStream in = null; //实例化一个字节输入流 OutputStream out = null; //实例化一个字节输出流 DataInputStream din = null; //创建一个DataInputStream输入流 DataOutputStream dout = null; //创建一个DataOutputStream输出流 try { serverSocket = new ServerSocket(10010); //创建服务器套接字并绑定到10010端口 while (true){//循环等待客户端连接 /* 等待客户端套接字继续连接,连接成功后返回连接的客户端套接字实例 */ System.out.println("等待连接......"); client = serverSocket.accept(); //接收到的套接字,赋给当前类的客户端套接字 System.out.println("连接成功"); in = client.getInputStream(); //接收到的数据赋给字节输入流 din = new java.io.DataInputStream(in); //实例化一个DataInputStream输入流 out = client.getOutputStream(); //接收到的数据赋给字节输出流 dout = new DataOutputStream(out); //实例化一个DataOutputStream输出流 dout.writeUTF("连接成功,可以上传文件!"); while (true){ String mess = din.readUTF(); //从客户端读取信息 System.out.println("文件路径及名字:"+mess); FileUpload fil = new FileUpload(); //实例化文件上传类 /* 将给定的源文件拷贝到目标目录文件*/ File sourceFile = new File(mess); //给定的源文件 String savePath = "e:/files2/copyFile/";//文件将会上传到的目录(其实是复制) String fileName = "复制的文件.txt"; //目标的文件名称 //调用上传文件的方法(其实是复制)并用布尔值接收执行状态 boolean bool1 = fil.copyFile(sourceFile,savePath,fileName); String resMess2 = String.valueOf(bool1); //将布尔值转换为字符串 dout.writeUTF("服务端返回的信息是 "+resMess2); //把执行状态返回到客户端 } } } catch (IOException e) { e.printStackTrace(); } // finally { // try { // dout.close(); // din.close(); // out.close(); // in.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } } }
/** * 1使用Eclipse 集成开发工具建立一个服务器端控制台应用程序,此程序能够等待并接收N个客户端的连接, * 并在与客户端连接成功后,向客户端发送连接成功的消息(如: 连接成功,可以上传文件)。 * 服务器端在接收到客户端上传的文件后能够将文件保存到服务器端系统某硬盘位置, 并应考虑上传文件不 * 能与已经存在的文件重名. 在文件上传成功或失败时应能向客户端发送相应的信息。在客户端断开连接后 * 应能够将客户端对象在服务器内存中释放。 * * 2使用Eclipse 集成开发工具建立一个客户端控制台应用程序, 此程序在启动运行后应能够实现与上述 * 服务器端应用程序进行连接,在服务器返回连接成功后可以实现将用户选择的客户端机器上的文件上传到 * 服务器。文件上传成功或失败应能够接收到服务器返回的信息,并且可以再次选择上传新文件及选择与服 * 务器端断开连接并退出系统,退出系统时应给出提示,在用户确认后退出. */ package until; import java.io.*; import java.net.InetSocketAddress; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { Scanner scan = new Scanner(System.in); //new一个Scanner接收用户输入 Socket client = null; //客户端套接字 client = new Socket(); //创建未连接的套接字对象 System.out.println(client.isBound()); //输出客户团套接字是否绑定,已绑定输出true,否则输出false //实例化一个IP地址address和和端口号10010绑定,因为是本机,所以只能使用localhost InetSocketAddress address = new InetSocketAddress("localhost",10086); InputStream in = null; OutputStream out = null; DataInputStream din = null; DataOutputStream dout = null; /* 远程服务器的ip地址及端口号 */ InetSocketAddress serverAddress = new InetSocketAddress("localhost",10010); try { client.bind(address); //将未连接的客户端套接字对象绑定到localhost:10010地址和端口号上 System.out.println(client.isBound()); //输出客户团套接字是否绑定,已绑定输出true,否则输出false /* 尝试连接到远程服务器 */ client.connect(serverAddress); in = client.getInputStream(); //基于客户端的套接字实例获取输入流 out = client.getOutputStream(); //基于客户端的套接字实例获取输出流 din = new DataInputStream(in); //基于in创建数据输入流 dout = new DataOutputStream(out); //基于out创建数据输出流 String resMess = din.readUTF(); //从服务器读取连接成功的信息 System.out.println("服务器返回信息是 "+resMess); while(true){ /* 将给定的源文件拷贝到目标目录文件,模拟上传文件的功能 */ System.out.println("请输入要上传的源文件路径和源文件名称,如e:/files/一个测试文件.txt"); String mess = scan.next(); dout.writeUTF(mess); //向服务器发送信息 String resMess2 = din.readUTF(); //从服务器读取信息 System.out.println("文件是否上传成功 "+resMess2); } } catch (IOException e) { e.printStackTrace(); } // finally { // try { // dout.close(); // din.close(); // out.close(); // in.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } } }
/** * 定义一个文件上传类,用来存文件上传的方法供服务器调用 */ package until; import java.io.*; public class FileUpload { public boolean copyFile(File sourceFile, String savePath, String fileName) { InputStream in = null; //文件输入流 OutputStream out = null; //文件输出流 File copyFile = null; //目标写入的文件对象 File path = new File(savePath); //新建一个文件路径对象 if (sourceFile.exists()) { //判断目标文件是否存在 if (!path.exists()) { //判断要拷贝的目录是否存在 path.mkdirs(); //如果不存在就新建这个目录 } try { in = new FileInputStream(sourceFile); //基于目标文件建立文件输入流 /** * 避免文件重名被覆盖,可以使用系统时间的毫秒作为文件的前缀 */ //建立目标写入的文件对象 copyFile = new File(path + "/" + fileName); out = new FileOutputStream(copyFile); //建立基于目标文件的输出流 byte bys[] = new byte[1024]; //临时存储字节数据的缓冲区 int count = 0; //记录读取内容的临时变量 while ((count = in.read(bys, 0, bys.length)) != -1) { out.write(bys, 0, count); //将临时缓冲区的内容写入到目标文件中 } System.out.println("文件复制完成"); return true; } catch (IOException e) { e.printStackTrace(); } finally { try { out.close(); in.close(); } catch (IOException e) { e.printStackTrace(); } } return true; }else{ return false; } } }
------------------------------------------------分割线-----------------------------------------------------------
package com.cetc.copy; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; import java.util.UUID; public class Server { public static void main(String[] args) throws IOException { ServerSocket server=new ServerSocket(1234); Socket client=server.accept(); BufferedReader br=new BufferedReader(new InputStreamReader(client.getInputStream())); PrintStream printStream=new PrintStream(client.getOutputStream()); //从客户端接收发送文件名 String fileName=br.readLine();//a.png System.out.println("客户端要上传文件:"+fileName); System.out.println("是否同意上传?(y/n)"); Scanner scanner=new Scanner(System.in); String yn=scanner.next(); if (yn.equalsIgnoreCase("y")){ System.out.println("请录入要保存的地址"); String path=scanner.next(); File dir=new File(path); dir.mkdirs(); //重新处理上传的文件名 String extName=fileName.substring(fileName.lastIndexOf(".")); String prefix= UUID.randomUUID().toString().replace("-",""); fileName=prefix+extName; File file=new File(dir,fileName); printStream.println("同意"); //保存文件 BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(file)); BufferedInputStream bis=new BufferedInputStream(client.getInputStream()); int x=bis.read(); while (x!=-1){ bos.write(x); x=bis.read(); } bis.close(); bos.close(); System.out.println("接收文件完成"); }else{ printStream.println("拒绝"); } } }
package com.cetc.copy; import java.io.*; import java.net.Socket; import java.util.Scanner; import java.util.UUID; public class Client { public static void main(String[] args) throws IOException { Socket client=new Socket("localhost",1234); PrintStream printStream=new PrintStream(client.getOutputStream()); Scanner scanner=new Scanner(System.in); System.out.println("请输入要上传的文件名"); String fileName=null; File file=null; while (true){ fileName= scanner.nextLine(); file=new File(fileName); if (file.exists()) break; System.out.println("文件不存在"); } printStream.println(file.getName()); //接收服务器端返回的信息 BufferedReader reader=new BufferedReader(new InputStreamReader(client.getInputStream())); String yn=reader.readLine(); if (yn.equals("同意")){ System.out.println("服务器端允许上传,开始上传...."); BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file)); int x=bis.read(); while (x!=-1){ printStream.write(x); x=bis.read(); } bis.close(); printStream.close(); System.out.println("上传完成"); }else{ System.out.println("服务器拒绝接收文件"); } } }