IP地址
- ip地址:唯一标识主机
- ip表示:对于IPV4 4个字节(32位表示)一个字节8位,1个字节0-255
- ip地址的组成=网络地址+主机地址
比如:192.168.16.69 182.168.16 为网络地址 69为主机地址 - ipv6是互联网工程任务组设计的用于替代ipv4的下一代协议,其地址数量可以为全世界的每一粒沙子编上一个地址,ipv6使用128位表示地址,16个字节,是ipv4的四倍
域名和端口号
域名
- www.baidu.com
- 好处:方便记忆,解决了记IP的困难
- 概念:将IP地址映射成域名
端口号
- 概念:用于标识计算机上某个特定的网络程序
- 表示形式:0-65535 [0,2^16-1]
- 0-1024 已经被占用 在网络开发中不要使用0-1024的端口
- 常见的网络程序端口号:tomact:8080 mysql:3306 oracle:1521 sqlserver:1433
TCP和UDP
TCP协议:传输控制协议
- 使用TCP协议前,须先建立TCP连接,形成数据传输通道
- 传输前,采用"三次握手"的方式,是可靠的
- TCP协议进行通信的两个应用程序:客户端和服务器
- 在连接中可以进行大量的数据传输
- 传输完毕,需要释放已经建立的连接,效率低
三次握手: UDP协议:用户数据协议
- 将数据,源,目的封装成数据包,不需要建立连接
- 每个数据包的大小限制在64K内,不适合传输大量的数据
- 因无需连接,故是不可靠的
- 发送数据结束时无需释放资源(因为不是面向连接的),速度快
InetAddress
- 获取本机的InetAddress对象 getLocalHost
- 根据指定主机名/域名获取ip地址对象 getByName
- 获取InetAddress对象的主机名 getHostName
- 获取InetAddress对象的地址 getHostAddress
package JavaStudy;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class API_ {
public static void main(String[] args) throws UnknownHostException {
InetAddress localHost=InetAddress.getLocalHost();
System.out.println(localHost);
InetAddress host1=InetAddress.getByName("DESKTOP-1BPR8C4");
System.out.println("host1="+host1);
InetAddress host2= InetAddress.getByName("www.baidu.com");
System.out.println("host2="+host2);
String hostAddress=host2.getHostAddress();
System.out.println("host2 对应的ip=" +hostAddress);
String hostName=host2.getHostName();
System.out.println("host2对应的主机名/域名="+hostName);
}
}
获取本机的信息(主机名/ip) 通过域名获取远程服务器的ip
Socket
- 基于客户端–服务端额网络通信
- 底层使用的是TCP/IP协议
- 应用场景举例:客户端发送数据,服务端接收并显示
把数据写入通道:socket.getOutputStream() 把数据从通道中读出:socket.getInputStream()
TCP字节流编程
需求: 编写一个服务器端和一个客户端,服务器端在9999端口监听,客户端连接到服务器端,发送 “hello server” 并接受服务器端回发的"hello,client" 再退出 服务器端接收到客户端发送的信息 输出并发送"hello,client" 再退出
- 服务端在本机的9999端口监听,等待连接,在没有客户端连接9999端口时,程序会阻塞,等待连接
- 客户端连接服务端(ip,端口)
- 客户端连接上后,生成socket,通过socket.getOutputStream(),通过输出流写入到数据通道
- 设置写入结束标记,socket.shutdoenOutput()
- 服务端通过Socket.getInputStream()读取客户端写入到数据通道的数据,显示
- 关闭socket和io…
- 服务端再通过socket.getOutputStream()写入到数据通道
- 设置写入结束标记,socket.shutdoenOutput()
- 客户端再通过Socket.getInputStream()读取客户端写入到数据通道的数据,显示
- 关闭socket和io…
服务器:
package JavaStudy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(9999);
Socket socket=serverSocket.accept();
InputStream inputStream=socket.getInputStream();
byte[] buf=new byte[1024];
int readLen=0;
while((readLen=inputStream.read(buf))!=-1)
{
System.out.println(new String(buf,0,readLen));
}
OutputStream outputStream=socket.getOutputStream();
outputStream.write("hello,client".getBytes());
socket.shutdownOutput();
inputStream.close();
outputStream.close();
serverSocket.close();
socket.close();
}
}
客户端:
package JavaStudy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketTCP01Client {
public static void main(String[] args) throws IOException {
Socket socket= new Socket(InetAddress.getLocalHost(),9999);
OutputStream outputStream=socket.getOutputStream();
outputStream.write("hello server".getBytes());
socket.shutdownOutput();
InputStream inputStream=socket.getInputStream();
byte[] buf=new byte[1024];
int len=0;
while((len=inputStream.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}
outputStream.close();
inputStream.close();
socket.close();
System.out.println("客户端退出");
}
}
TCP字符流编程
与字节流一样的需求 这里需要采用转换流将字节输入流和字节输出流分别转换为字符输入流和字符输出流 服务端:
package JavaStudy;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(9999);
Socket socket=serverSocket.accept();
InputStream inputStream=socket.getInputStream();
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
String s=bufferedReader.readLine();
System.out.println(s);
OutputStream outputStream=socket.getOutputStream();
BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello client 字符流");
bufferedWriter.newLine();
bufferedWriter.flush();
bufferedReader.close();
bufferedWriter.close();
serverSocket.close();
socket.close();
}
}
客户端:
package JavaStudy;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketTCP01Client {
public static void main(String[] args) throws IOException {
Socket socket= new Socket(InetAddress.getLocalHost(),9999);
OutputStream outputStream=socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello server 字符流");
bufferedWriter.newLine();
bufferedWriter.flush();
socket.shutdownOutput();
InputStream inputStream=socket.getInputStream();
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
String s= bufferedReader.readLine();
System.out.println(s);
bufferedReader.close();
bufferedWriter.close();
socket.close();
System.out.println("客户端退出");
}
}
网络文件上传
TCP通信的文件上传控制 原理:客户端读取本地的文件,把文件上传到服务器,服务器再把上传的文件保存到服务器的硬盘上 基本步骤:
- 客户端使用本地的字节输入流,读取需要上传的文件
- 客户端使用网络网络字节输出流,把读取的文件上传到服务器
- 服务器使用网络字节输入流,读取客户端上传的文件
- 服务器使用本地字节输出流,把读取到的文件,保存到服务器的硬盘上
- 服务器使用网络字节输出流,给客户端写一个"上传成功"
- 客户端使用网络字节输入流,读取服务器返回写的数据
注意: 客户端和服务器和本地硬盘进行读写,需要使用自己创建的字节流对象(本地流) 客户端和服务器之间进行读写,必须使用Socket中字节流对象(网络流)
服务器:
package JavaStudy;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server=new ServerSocket(8888);
Socket socket=server.accept();
InputStream is=socket.getInputStream();
File file=new File("d:\\upload");
if(!file.exists())
{
file.mkdirs();
}
FileOutputStream fos=new FileOutputStream(file+"\\1.jpg");
int len=0;
byte[] bytes=new byte[1024];
while((len=is.read(bytes))!=-1)
{
fos.write(bytes,0,len);
}
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
server.close();
socket.close();
}
}
客户端:
package JavaStudy;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("D:\\image\\bg2.jpg");
Socket socket=new Socket(InetAddress.getLocalHost(),8888);
OutputStream os=socket.getOutputStream();
int len=0;
byte[] bytes=new byte[1024];
while((len=fis.read(bytes))!=-1)
{
os.write(bytes,0,len);
}
socket.shutdownOutput();
InputStream is=socket.getInputStream();
while((len=is.read(bytes))!=-1)
{
System.out.println(new String(bytes,0,len));
}
fis.close();
socket.close();
}
}
文件上传优化分析
可自定义一个文件的命名规则:防止同名的文件覆盖 规则:域名+毫秒值+随机数
String filename="itcast"+System.currentTimeMillis()+new Random(999999)+"jpg";
FileOutputStream fos=new FileOutputStream(file+"\\filename");
可以让服务器一直处于监听状态,死循环accept方法,有一个客户端上传文件,就保存一个文件,但这样效率比较低下,所以我们可以采用多线程来提高效率 有一个客户端上传文件,就开启一个线程,完成文件的上传 服务器:
package JavaStudy;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server=new ServerSocket(8888);
while(true){
Socket socket=server.accept();
new Thread(new java.lang.Runnable() {
@Override
public void run() {
try{
InputStream is=socket.getInputStream();
File file=new File("d:\\upload");
if(!file.exists())
{
file.mkdirs();
}
String filename="itcast"+System.currentTimeMillis()+new Random(999999)+".jpg";
FileOutputStream fos=new FileOutputStream(file+"\\"+filename);
int len=0;
byte[] bytes=new byte[1024];
while((len=is.read(bytes))!=-1)
{
fos.write(bytes,0,len);
}
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
socket.close();
}
catch(IOException e)
{
System.out.println(e);
}
}
}).start();
}
}
}
nestat指令
- nestat-an 可以查看当前主机网络情况,包括端口监听情况和网络连接情况
- nestat-an|more 可以分页显示
- 要求在dos控制台下执行win+r
|