网络编程简介
/** * @brief * 网络编程 三大组件 * * 1, IP : 最大字节255, 默认得 127.0.0.1 ,ping不通网卡出问题了 * ipv4: 四段得ip, ipv6: 四段不够用了,定义了六段得 * 网络中设备得标识:不容易记忆,可用主机名,本地回环地址:127.0。0.1 主机名:localhost * * $ ping 127.0.0.1 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=1.39 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.029 ms * * 2,逻辑端口 0-65535 (0-1024被占用了,最好不用)web:8080 可以改 * * 3,通信规则 tcp/ip ,udp * * OSI参考模型 * TCP/IP参考模型 * $ javac Inet.java Command 'javac' not found, but can be installed with: sudo apt install openjdk-11-jdk-headless # version 11.0.15 10-0ubuntu0.20.04.1, or sudo apt install default-jdk # version 2:1.11-72 sudo apt install openjdk-16-jdk-headless # version 16.0.1 9-1~20.04 sudo apt install openjdk-17-jdk-headless # version 17.0.3 7-0ubuntu0.20.04.1 sudo apt install openjdk-8-jdk-headless # version 8u312-b07-0ubuntu1~20.04 sudo apt install openjdk-13-jdk-headless # version 13.0.7 5-0ubuntu1~20.04 sudo apt install ecj # version 3.16.0-1 * * $ uname -rs Linux 5.10.16.3-microsoft-standard-WSL2 $ cat /etc/issue Ubuntu 20.04.4 LTS n l * * UDP : 聊天,视频会议 * 1,将数据及源目的封装成数据包,不需要建立连接 * 2,每个数据包的大小限制在 64K 内 * 3,没有连接,因此是不可靠的 * 4,不需要建立连接,速度快 * * TCP:120打电话,下载 * 1,建立连接,形成传输数据的通道 * 2,在连接中进行大数据传输 * 3,通过三次握手完成连接,是可靠协议 * 4,必须建立连接,效率会低 * * Socket * 1,socket为网络服务提供一种机制 * 2,通信的两端都有socket * 3,网络通信其实就是socket间的通信 * 4,数据在两个socket间通过IO传输 */
UDP案例
案例1:UDP传输
Send端
代码语言:javascript复制//UDP传输 Send
class IPDemo
{
public static void main(String[] args) throws Exception
{
//获取本机
InetAddress i = InetAddress.getLocalHost();
System.out.println(i.toString());
System.out.println("address: " i.getHostAddress());
System.out.println("name: " i.getHostName());
//获取任意机器
//不在同一网段,解析不出名字
InetAddress ia = InetAddress.getByName("www.baidu.com");//www.baidu.com
System.out.println(ia.toString());
System.out.println("address: " ia.getHostAddress());
System.out.println("name: " ia.getHostName());
//UDP send
/**
* 思路:
* 1,建立udpsocket服务
* 2,提供数据,并将数据封装到数据包中
* 3,通过socket服务的发生功能将数据包发出去
* 4,关闭资源
*/
//1, 创建 udp服务,通过 DatagramSocket对象
DatagramSocket ds = new DatagramSocket();
//2,确定数据,并封装成数据包
byte[] buf = "udp ge men lai le".getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("172.29.194.96"),10000);
//3,通过socket服务,将已有的数据包发生出去,通过send方法
ds.send(dp);
//4, 关闭资源
ds.close();
}
}
Rece端
代码语言:javascript复制class IPRece
{
public static void main(String[] args) throws Exception
{
//UDP rece
//1, 创建 udp服务,建立端点,通常会监听一个端口
DatagramSocket ds = new DatagramSocket(10000);
while(true)
{
//2, 定义数据包,用来存储数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3,通过 receive方法将收到数据存入数据包中
ds.receive(dp);
//4, 通过数据包的方法获取其中的数据
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(ip "::" data "::" port);
}
//5,关闭资源
//ds.close();
}
}
案例2:键盘录入
Send端
代码语言:javascript复制//键盘录入
class UdpSend
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket();
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = bufr.readLine()) != null)
{
if("886".equals(line))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("172.29.194.96"),10001);
ds.send(dp);
}
ds.close();
}
}
Rece端
代码语言:javascript复制class UdpRece
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds =new DatagramSocket(10001);
while(true)
{
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
System.out.println(ip "::" data);
}
}
}
案例3:聊天系统
Send端 多线程定义:是个模板
代码语言:javascript复制class Send implements Runnable
{
private DatagramSocket ds;
public Send(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
DatagramSocket ds = new DatagramSocket();
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = bufr.readLine()) != null)
{
if("886".equals(line))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("172.29.194.96"),10001);
ds.send(dp);
}
}
catch (Exception e)
{
throw new RuntimeException("send fail");
}
}
}
Rece端 多线程定义:是个模板
代码语言:javascript复制class Rece implements Runnable
{
private DatagramSocket ds;
public Rece(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
while(true)
{
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
System.out.println(ip "::" data);
}
}
catch (Exception e)
{
throw new RuntimeException("rece fail");
}
}
}
调用
代码语言:javascript复制class ChatDemo
{
public static void main(String[] args) throws Exception
{
DatagramSocket sendSocker = new DatagramSocket();
DatagramSocket receSocker = new DatagramSocket(10001);
new Thread(new Send(sendSocker)).start();
new Thread(new Rece(receSocker)).start();
}
}
TCP案例
案例1:基本传输
//TCP传输 /** * 客户端Socket和服务端ServerSocket * 建立客户端和服务器端 * 建立连接后,通过Socket中的IO 流进行数据的传输 * 关闭socket * 同样,客户端与服务端是两个独立的应用程序 */ /** * 客户端: 通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机 因为tcp是面向连接的,所以在建立socket服务时,就要有服务端存在,并连接成功 形成通路后,在该通道进行数据的传输 */
client
代码语言:javascript复制 class TcpClient
{
public static void main(String[] args) throws Exception
{
//创建客户端socket服务,指定目的主机和端口
Socket s = new Socket("",10003);
//为了发送数据,应该获取socket流中的输出流
OutputStream out = s.getOutputStream();
out.write("tcp ge men lai le".getBytes());
//服务端返回信息
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
/** * 服务端: * 1,建立服务端的 socket服务,ServerSocket * 并监听一个端口 * 2,获取连接过来的客户端对象 * 通过 ServerSocket的accept方法,没有连续就会等,所以这个方法是阻塞的 * 3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到客户端对象的读取流来读取发过来的数据 * 4,关闭服务端 */
Server
代码语言:javascript复制 class TcpServer
{
public static void main(String[] args) throws Exception
{
//建立服务端 socket服务,并监听一个端口
ServerSocket ss = new ServerSocket(10003);
//通过accept方法获取连接过来的客户端对象
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip "....connected");
//获取客户端发送来的数据,使用客户端对象的读取来读取数据
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);//阻塞的
System.out.println(new String(buf,0,len));
//给客户端反馈信息
OutputStream out = s.getOutputStream();
Thread.sleep(10000);
out.write("rece !".getBytes());
s.close();
ss.close();
}
}
案例2:文本转换器
* * 建立一个文本转换器,客户端给服务端发送文本,服务端会将文本转成大写返回给客户端, * 而且客户端可以不断地进行文本转换,当客户端输入 over时,转换结束 * *步骤: 1,建立服务 2,获取键盘输入 3,将数据发送服务端 4,获取服务端返回地大写数据 5,结束,关资源 都是文本,用IO,提高效率 ,加入缓冲 */
client
代码语言:javascript复制class TransClient
{
public static void main(String[] args) throws Exception
{
Socket s =new Socket("127.0.1.1",10006);
//定义读取键盘数据地流对象
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//定义目的,将数据写入到 socket输出流,发送服务端
BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//定义一个socket读取流,读取服务端返回地大写信息
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = bufr.readLine()) != null)
{
if("over".equals(line))
break;
bufOut.write(line);
bufOut.newLine();//换行
//数据写入缓冲区进行刷新
bufOut.flush();
String str = bufIn.readLine();
System.out.println("server: " str);
}
bufr.close();
s.close();
}
}
Server
代码语言:javascript复制class TransServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10006);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip "....connected");
//读取socket读取流中地数据
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//定义目的,socket输出流,将大写数据写入到 socket输出流,并发送给客户端
BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//替换上面一行
//PrintWrite out = new PrintWrite(s.getOutputStream,true);
String line = null;
while((line = bufIn.readLine()) != null)
{
System.out.println(line);
bufOut.write(line.toUpperCase());
bufOut.newLine();//换行
bufOut.flush();
//替换上面三行
// out.println(line.toUpperCase());
}
s.close();
ss.close();
}
}
/** * 出现问题: * 客户端和服务端都在莫名等待 * * 原因: * 因为客户端和服务端都有阻塞方法,这些方法没得读到结束标记,一直在等待,导致两端都在等待 */
案例3:图片传输
/** * 客户端: 1,服务端点 2,读取客户端已有的图片数据 3,通过 socket 输出流将数据发给服务端 4,读取服务端反馈信息 5,关闭 */
client
代码语言:javascript复制class PicClient
{
public static void main(String[] args) throws Exception
{
if (args.length != 1)
{
System.out.println("select one jpg img");
return;
}
File file = new File(args[0]);
if (!(file.exists() && file.isFile()))
{
System.out.println("file not ok");
return;
}
if (!file.getName().endsWith(".jpg"))
{
System.out.print("geshi img not ok");
return;
}
if (file.length() > 1024*1024*5)
{
System.out.println("big");
return;
}
Socket s =new Socket("127.0.1.1",8003);
FileInputStream fis = new FileInputStream(file);
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1)
{
out.write(buf,0,len);
}
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn,0,num));
fis.close();
s.close();
}
}
代码语言:javascript复制/**服务端 * * 这个服务端有个局限性,当A客户端连接上以后,被服务端获取到,服务端执行具体流程 * 这是B客户端连接,只有等待。 * 因为服务端还没有处理完A客户端的请求,还有循环回来执行下次 accept方法,所以暂时 * 获取不到B客户端对象 * * 那么为了可以让多个客户端同时并发访问服务端 * 服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求 * 如何定义线程? * 只要明确了每一个客户端要在服务端执行的代码即可,将代码放入run中 */
class PicThread implements Runnable
{
private Socket s;
PicThread(Socket s)
{
this.s = s;
}
public void run()
{
int count = 1;
String ip = s.getInetAddress().getHostAddress();
try
{
System.out.println(ip "...connected");
InputStream in = s.getInputStream();
File file = new File(ip "(" (count) ")" ".jpg");
while(file.exists())
file = new File(ip "(" (count ) ")" ".jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while((len = in.read(buf)) != -1)
{
fos.write(buf,0,len);
}
OutputStream out = s.getOutputStream();
out.write("upload sucess".getBytes());
fos.close();
s.close();
}
catch(Exception e)
{
System.out.println(ip "...not connected");
}
}
}
class PicServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(8003);
while(true)
{
Socket s= ss.accept();
new Thread(new PicThread(s)).start();
}
//ss.close();
}
}
案例4:键盘录入
代码语言:javascript复制/*** * 需求分析: * 客户端通过键盘录入用户名 * 服务端对这个用户名进行校验 * * 如果该用户名存在,则在服务端显示XXX,已经登陆 * 并在客户端显示XXX 欢迎光临 * * 如果用户不存在,在服务端显示XXX,尝试登陆 * 并在客户端显示 XXX 该用户不存在 * * 最多就登录三次 */ client
class LoginClient
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("172.23.236.114",107);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
for(int x =0; x <3; x )
{
String line = bufr.readLine();
if(line == null)
break;
out.println(line);
String info = bufIn.readLine();
System.out.println("info:" info);
if(info.contains("欢迎"))
break;
}
bufr.close();
s.close();
}
}
//服务端封装原理模板
代码语言:javascript复制//服务端封装原理模板
class UserThread implements Runnable
{
private Socket s;
UserThread(Socket s)
{
this.s = s;
}
public void run()
{
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip "....connected");
try
{
for(int x=0; x<3;x )
{
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String name = bufIn.readLine();
System.out.println(name "....name");
if (name==null)
break;
BufferedReader bufr = new BufferedReader(new FileReader("2.txt.txt"));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line =null;
boolean flag = false;
while((line=bufr.readLine()) != null)
{
if(line.equals(name))
{
flag = true;
break;
}
}
if(flag)
{
System.out.println(name ",已登录");
out.println(name ",欢迎光临");
}
else
{
System.out.println(name ",尝试登录");
out.println(name ",用户名不正确");
}
}
s.close();
}
catch(Exception e)
{
System.out.println(ip "...not connected");
}
}
}
class LoginServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(107);
while(true)
{
Socket s= ss.accept();
new Thread(new UserThread(s)).start();
}
}
}
案例5:浏览器客户端
/** * 客户端:浏览器 * 输入:https://172.23.236.114:11000/ * 或者终端输入:telnet 172.23.236.114 11000 * 服务端:自定义
*/
代码语言:javascript复制class ServerDemo
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(11000);
Socket s =ss.accept();
System.out.println(s.getInetAddress().getHostAddress());
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("<font color='red' size='7'>客户端你好<.font>");
s.close();
ss.close();
}
}