一、网络编程概念:
io : 电脑内存和电脑的外部存储设备之间的距离传输.
socket : 网络编程 , 实现两台电脑的内存, 通过互联网进行数据传输 .
计算机网络 :
把分布在不同地理区域的计算机与专门的外部设备用通信线路互联成一个规模大 , 功能强的网络系统 , 从而使众多的计算机可以方便的互相传递信息,共享硬件,软件,数据信息等资源 .
计算机网络中两台电脑之间进行数据传输前提:
- a电脑给b电脑发送数据 不但需要知道b的ip地址 还需要声明接受数据的软件 .
- a电脑必须获取b电脑的ip地址 .
- a电脑通过互联网指定b的ip地址 ,发送数据0101010101001010100101 .
- b电脑中有n个软件可以接受数据 不同软件解析数据的格式(不同软件之间制定的数据传输协议不同)是不同的 .
协议:数据传输双方达成的一种共识
ip地址:ipV4 : 4个字节来表示ip .
ipv6 : 8个2个字节表示ip .
本地ip:当前主机: localhost 127.0.0.1 。
port: 端口 ,逻辑端口;为当前电脑中安装的所有软件分配一个逻辑端口(编号) 用于实现当前软件与互联网进行数据传输, 0-65535 1000以下被操作系统使用 。
什么是网络通信协议
计算机网络中实现通信必须有一些约定即通信协议,对速率、传输代码、代码结构、传 输控制步骤、出错控制等制定标准。
TCP: transmission control protocol,是面向连接的 端对端的 可靠的字节流传输协议。
UDP: user datagrame protocol ,是无需连接的 不可靠的 报文流传输协议。
二、TCP服务器首次体验
1.TCP服务器端
主要是两个类:Sokect ServerSocket 类似于打电话
服务器端:部署软件的电脑(提供服务 被访问)
客户端:提供互联网去主动访问服务器端的资源(主动访问)
* tcp:客户端 类似于打电话的呼叫者
* 1 拨通对方手机 创建连接
* 2 接受和发送信息
* 3 挂断电话
* tcp:客户端
* 1: 创建socket对象(传输通道) 指定对方的ip+port
* 2: 获取socket对象中的输入和输出流来接受和发送数据
* 3: 关闭socket:socket.close();
//1:创建serversocket对象 指定开启的端口
ServerSocket server=new ServerSocket(10086);
//2:调用serversocket的accept方法等待连接 获取socket对象
Socket socket=server.accept();
//3: 获取socket对象中的输入和输出流来接受和发送数据
//给客户端说话
OutputStream out=socket.getOutputStream();
out.write("客户端你好!有什么事情吗?".getBytes("GBK"));
//out.close();
//接受客户端的反馈:默认给我只说一句 不循环了
InputStream in=socket.getInputStream();
byte[] arr=new byte[1024];
int n=in.read(arr);
System.out.println("客户端反馈:"+new String(arr, 0, n,"GBK"));
//in.close();
//4:关闭服务:serversocket.close()
server.close();
2.TCP客户端
1: 创建socket对象(传输通道) 指定对方的ip+port
Socket socket=new Socket("localhost", 10086);
// 2: 获取socket对象中的输入和输出流来接受和发送数据
//接受服务器发送的数据
InputStream in=socket.getInputStream();
byte[] arr=new byte[1024];
int n=in.read(arr);
System.out.println("客户端接受到服务器端的信息:"+new String(arr, 0, n,"gbk"));
//给服务器端回话
OutputStream out=socket.getOutputStream();
out.write("没啥事!拜拜!".getBytes("GBK"));
// 3: 关闭socket:socket.close();
socket.close();
3.运行TCP
注意1:先开启服务器端 再开启客户端:::服务器端的ServerScoket.accept方法是阻塞方法。
注意2:服务器端和客户端是两个console 可以切换。
三、TCP二次体验
客户端循环从键盘获取信息 当读到886结束。
//0 从键盘获取数据
Scanner sr=new Scanner(System.in);
// 1: 创建socket对象(传输通道) 指定对方的ip+port
Socket socket=new Socket("localhost", 10086);
//获取对方的ip_port和本地的ip_port
String ip=socket.getInetAddress().getHostName();int port=socket.getPort();
String local_ip=socket.getLocalAddress().getHostName();int local_port=socket.getLocalPort();
// 2: 获取socket对象中的输入和输出流来接受和发送数据
OutputStream out=socket.getOutputStream();
InputStream in=socket.getInputStream();
byte[] arr=new byte[1024];
while(true) {
String line=sr.next();//获取键盘输入的信息
out.write(line.getBytes("GBK"));//通过socket把获取的信息写出去
int n=in.read(arr);//从输入流中读取信息
System.out.println("客户端("+local_ip+"_"+local_port+")接受到服务器端("+
ip+"_"+port+")的信息:"+new String(arr, 0, n,"gbk"));
if(line.endsWith("886")) { break; } //获取的信息中以886结尾 就结束交互
}
// 3: 关闭socket:socket.close();
socket.close();
服务器端循环接受信息 把信息大小写转换后 再发给客户端 读到886结束。
//1:创建serversocket对象 指定开启的端口
ServerSocket server=new ServerSocket(10086);
//2:调用serversocket的accept方法等待连接 获取socket对象
Socket socket=server.accept();
//获取对方的ip_port和本地的ip_port
String ip=socket.getInetAddress().getHostName(); int port=socket.getPort();
String local_ip=socket.getLocalAddress().getHostName();int local_port=socket.getLocalPort();
//3: 获取socket对象中的输入和输出流来接受和发送数据
//获取客户端的信息
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
byte[] arr=new byte[1024];
while(true) {
int n=in.read(arr);//从socket中读取信息
String message=new String(arr, 0, n,"GBK");
System.out.println("服务器端("+local_ip+"_"+local_port+"):接受到客户端("+
ip+"_"+port+")数据是:"+message);
message=changeStr(message);//对信息进行转换
out.write(message.getBytes("GBK"));//把转换后的信息发给客户端
if(message.endsWith("886")) { break; }
}
//4:关闭服务:serversocket.close()
server.close();
//通过tcp实现文件上传: 客户端通过fileinputstream读取源文件信息 把信息通过socket的输出流发给服务器端
// 创建fileoutputstream关联目的文件 获取socket 从socket的输入流中 读信息
// 把读取的信息通过fileoutputstream写到目的文件中
}
private static String changeStr(String message) {
//频繁对字符进行修改 建议使用缓冲区
StringBuilder stb=new StringBuilder(message);
for (int i = 0; i < stb.length(); i++) {
char c=stb.charAt(i);
if(Character.isUpperCase(c)) {
c=Character.toLowerCase(c);
}else if(Character.isLowerCase(c)) {
c=Character.toUpperCase(c);
}
stb.setCharAt(i, c);
}
return stb.toString();
四、TCP再次体验:通过tcp实现文件上传
1.客户端
public static void main(String[] args) throws Exception {
fileUpload("src\\test\\1111.PNG");
}
private static void fileUpload(String fileName)throws Exception {
//实现文件的上传:
//通过输入流把源文件中的信息读到内存中 再通过socket的输出流把信息发给服务器端
File file=new File(fileName);
FileInputStream fin=new FileInputStream(file);//创建流关联源文件
Socket socket=new Socket("127.0.0.1", 10086);//创建socket指定服务器端的ip+端口
//获取socket的输入流和输出流
InputStream in=socket.getInputStream(); OutputStream out=socket.getOutputStream();
//需要先把文件名字发给服务器端 默认共识前1024个字节是文件名字
byte[] arrName=file.getName().getBytes("gbk");
out.write(arrName);
//一边读取源文件 一边通过socket的输出流把 信息发给服务器端
byte[] arr=new byte[1024]; int n;
while((n=fin.read(arr))!=-1) {
out.write(arr, 0, n);//把arr中有效的数据写出去
}
socket.shutdownOutput();//服务器端不知道什么时候结束:禁用输出流 服务器端的输入流就可以读取到末尾
//获取服务器端的反馈信息
n=in.read(arr);
System.out.println("接收到服务器端("+socket.getInetAddress().getHostName()+"_"
+socket.getPort()+")的反馈信息:"+new String(arr, 0, n));
//关闭socket:谁创建的谁关闭
fin.close(); socket.close();
}
}
2.服务器端
public static void main(String[] args) throws Exception {
fileUploadServer("d:\\test");
}
private static void fileUploadServer(String path) throws Exception{
//文件上传的服务器端:创建servletscoket 获取连接 通过连接的输入流获取上传文件的信息
// 创建文件输出流与目的文件关联 把socket中读取的信息 通过文件输出流写出去
// 写完 反馈 文件上传完毕
ServerSocket server=new ServerSocket(10086);//创建serversocket执行开启的端口
Socket socket=server.accept();//获取连接
//获取连接的输入和输出流
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
//前1024个字节是文件名字
byte[] arr=new byte[1024];
in.read(arr);
String fileName=new String(arr, "gbk");
fileName=fileName.trim();//去除两边的空格
//创建文件输出流与目的文件关联
File muDi=new File(path, fileName);
FileOutputStream fout=new FileOutputStream(muDi);
//一边从socket中读信息 一边把读取的信息通过fout写出去
int n;
while((n=in.read(arr))!=-1) {
fout.write(arr, 0, n);
}
//给客户端反馈 上传完毕
out.write(("上传文件("+fileName+"):成功!").getBytes("gbk"));
fout.close();
server.close();
五、UDP
*UDP: 主要学习两个类: DatagrameSocket 和 DatagramePacket
* *DatagrameSocket: 报文流的套接字 :udp的传输通道
* 构造方法:DatagramSocket(int port) 创建socket指定开启的端口
* 普通方法: void close() 关闭连接
* void receive(DatagramPacket p) 接受数据报
* void send(DatagramPacket p) 发送数据报
* InetAddress getInetAddress() 获取对方的ip
* InetAddress getLocalAddress() 获取本地的ip
* int getLocalPort() 获取本地的端口
* int getPort() 获取对方的端口
* DatagramePacket: 报文对象
构造方法: 参数没有ip+port的是用于接受的 有ip+port的是用于发送的
DatagramPacket(byte[] buf, int offset, int length)
用数组buf的从offset下标处开始length个字节来接受数据
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
把数组buf的从offset下标处开始的length个字节发送给ip为address的端口为port的程序
普通方法 : int getLenght() 获取有效字节个数
InetAddress getAddress() 获取对方的IP
int getPort() 获取对方的端口
public static void main(String[] args)throws Exception {
//循环的获取键盘输入的内容 然后通过socket发给10086端口 等待接受10086的反馈
Scanner sr=new Scanner(System.in);
DatagramSocket socket=new DatagramSocket(10010);
while(true) {
String line=sr.nextLine();//从键盘获取信息
//把信息封装成datagrampacket对象
byte[] arr=line.getBytes();
DatagramPacket packetSend
=new DatagramPacket(arr, 0, arr.length, InetAddress.getByName("localhost"), 10086);
//通过socket发出去
socket.send(packetSend);
//创建一个空的datagrampacket来接受数据
DatagramPacket packetReceive=new DatagramPacket(new byte[1024],0,1024);
socket.receive(packetReceive);
//解析数据 把packet关联的数组的前packet.getLength()个有效字节转换为字符串
String message=new String(packetReceive.getData(), 0, packetReceive.getLength());
System.out.println(socket.getLocalPort()+"接受到"+packetReceive.getPort()+"的信息:"+message);
if(line.endsWith("886")) {break;}
}
socket.close();
public static void main(String[] args)throws Exception {
//创建socket开启端口10086 接收到数据就大小写转换 转换完后再发送给对方 当接收到的数据以886结尾 结束循环
DatagramSocket socket=new DatagramSocket(10086);
while(true) {
//创建一个空的datagrampacket来接受数据
byte[] arr=new byte[1024];
DatagramPacket packetReceive=new DatagramPacket(arr, 0,1024);
socket.receive(packetReceive);//接受数据
String message=new String(arr, 0,packetReceive.getLength());//解析数据
System.out.println(socket.getLocalPort()+"接收到"+packetReceive.getPort()+"的信息是:"+message);
message=changeStr(message);//数据转换
arr=message.getBytes();
//把数据封装为datagrampakcet
DatagramPacket packetSend=new DatagramPacket(arr, 0,arr.length,
packetReceive.getAddress(), packetReceive.getPort());
socket.send(packetSend);//通过socket发送给对方
if(message.endsWith("886")) {break;}
}
socket.close();