一、网络编程
1.网络编程三要素
在网络通信协议下。不同计算机上运行的程序,可以进行数据传输
2.IP地址常用命令
- ipconfig
- Ping ip地址:检查网络是否连通
- 127.0.0.1 本地IP地址
3. InetAddress类
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Demo1 {
public static void main(String[] args) throws UnknownHostException {
InetAddress address=InetAddress.getByName("zfz");
String hostName = address.getHostName();
System.out.println("主机名为:"+hostName);
String hostAddress = address.getHostAddress();
System.out.println("Ip为:"+hostAddress);
}
}
二、UDP通讯程序
1.UDP发送数据
import java.io.IOException;
import java.net.*;
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1.找码头
DatagramSocket ds=new DatagramSocket();
//2.打包数据
// public DatagramPacket(byte[] buf, int length, InetAddress address, int port)
String str="朋友送的 好烟 好酒 好茶";
byte[] bytes = str.getBytes();
InetAddress address=InetAddress.getByName("127.0.0.1");
int port=10000;
DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,port);
//3.发送数据
ds.send(dp);
//发送完成
ds.close();
}
}
2.UDP接受数据
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ServerDemo {
/**
* 注意点:
* 1. 要先运行接收端 再运行发送端
* 2. 如果接收端再启动之后,没有收到数据 ,就会死等(阻塞状态)
* 3. 在接受数据时 可以调用getLength方法,表示接收到了多少字节
* 4.
*/
public static void main(String[] args) throws IOException {
//1.找码头
//表示接受端从10000端口接受数据
DatagramSocket ds=new DatagramSocket(10000);
//2.创建接受数据的箱子
// public DatagramPacket(byte[] buf, int length)
byte bytes[]=new byte[1024];
DatagramPacket dp=new DatagramPacket(bytes,bytes.length);
//3.接受数据并放到箱子中
System.out.println("--------接受前--------");
ds.receive(dp);
System.out.println("--------接受后--------");
//4.从箱子中拿出数据
//byte [] data=dp.getData();
int length=dp.getLength();
System.out.println(new String(bytes,0,length));
//5.接受完成
ds.close();
}
}
3.UDP_practice
3.1 发送端
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class ClientDemo {
public static void main(String[] args) throws IOException {
Scanner sc=new Scanner(System.in);
DatagramSocket ds=new DatagramSocket();
while (true) {
String str=sc.nextLine();
if (str.equals("886")){
break;
}
byte[] bytes = str.getBytes();
InetAddress address=InetAddress.getByName("127.0.0.1");
int port=10000;
DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,port);
ds.send(dp);
}
ds.close();
}
}
3.2 接受端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
DatagramSocket ds=new DatagramSocket(10000);
while (true) {
byte bytes[]=new byte[1024];
DatagramPacket dp=new DatagramPacket(bytes,bytes.length);
ds.receive(dp);
int length=dp.getLength();
System.out.println(new String(bytes,0,length));
}
}
}
4.UDP的三种通信方式
4.1 单播代码实现
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class ClientDemo {
public static void main(String[] args) throws IOException {
Scanner sc=new Scanner(System.in);
DatagramSocket ds=new DatagramSocket();
while (true) {
String str=sc.nextLine();
if (str.equals("886")){
break;
}
byte[] bytes = str.getBytes();
InetAddress address=InetAddress.getByName("127.0.0.1");
int port=10000;
DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,port);
ds.send(dp);
}
ds.close();
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
DatagramSocket ds=new DatagramSocket(10000);
while (true) {
byte bytes[]=new byte[1024];
DatagramPacket dp=new DatagramPacket(bytes,bytes.length);
ds.receive(dp);
int length=dp.getLength();
System.out.println(new String(bytes,0,length));
}
}
}
4.2 组播代码实现
import java.io.IOException;
import java.net.*;
public class ClientDemo {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
String str = "组播转发";
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("224.0.1.0");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);
ds.send(dp);
ds.close();
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
MulticastSocket ms=new MulticastSocket(10000);
DatagramPacket dp=new DatagramPacket(new byte[1024],1024);
//把当前计算机绑定一个组播地址,表示添加到这一组中
ms.joinGroup(InetAddress.getByName("224.0.1.0"));
ms.receive(dp);
byte [] data=dp.getData();
int length=dp.getLength();
System.out.println(new String(data,0,length));
}
}
4.3 广播代码实现
import java.io.IOException;
import java.net.*;
public class ClientDemo {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
String str = " 广播转发";
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("255.255.255.255");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);
ds.send(dp);
ds.close();
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.MulticastSocket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
MulticastSocket ms=new MulticastSocket(10000);
DatagramPacket dp=new DatagramPacket(new byte[1024],1024);
//把当前计算机绑定一个组播地址,表示添加到这一组中
ms.receive(dp);
byte [] data=dp.getData();
int length=dp.getLength();
System.out.println(new String(data,0,length));
}
}
三、TCP通讯程序
1.TCP通讯
1.1 TCP发送数据
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1.创建一个Socket对象
Socket socket=new Socket("127.0.0.1",10005);
//2.获取IO流写数据
OutputStream os = socket.getOutputStream();
os.write("hello".getBytes());
//3.释放资源
os.close();
socket.close();
}
}
1.2 TCP接受数据
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1. 创建Socket对象
ServerSocket socket=new ServerSocket(10005);
//2. 等待客户端连接
System.out.println("---------接受前--------");
//socket.accept()开启服务后 阻塞状态 等待就收 死等ing
Socket accept = socket.accept();
System.out.println("---------接受后--------");
//3.获得输入流都西昂
InputStream in = accept.getInputStream();
int b;
//如果客户端不执行close关闭操作 则服务端read方法也是阻塞状态 一直等着读取,会认为读取数据未结束
while ((b=in.read())!=-1){
System.out.print((char)b);
}
//4.释放资源
accept.close();
socket.close();
}
}
2.TCP 执行流程
3.TCP三次握手
三次握手简述:
- 第一次握手:客户端给服务器发送一个报文,告知服务器:客户端请求连接,服务器收到第一段报文后得出结论:客户端发送功能正常,服务器接收功能正常。
- 第二次握手:服务器收到报文后给客户端回复一个报文,告知客户端:“我服务器收到了你的请求,同意和你建立连接”。客户端收到第二段报文后得出结论:客户端发送和接收功能都正常,服务器的发送接收功能也都正常。(但此时服务器不能确认客户端的接收功能和自己的发送功能是否正常)。
- 第三次握手:客户端收到第二段报文后给服务器回复一个报文,告知服务器:“我客户端收到了你的回复,知道你同意连接,那我们开始连接吧!”服务器收到第三段报文后得出结论:客户端的接收功能和服务器的发送功能也都正常。所以当服务器收到第三个报文后,两边就建立起了TCP连接。
4.TCP四次挥手
4.TCP_practice
4.1客户端与服务端都接受与发送数据
import java.io.*;
import java.net.Socket;
public class ClientDemo {
public static void main(String[] args) throws IOException {
Socket socket=new Socket("127.0.0.1",9999);
OutputStream os = socket.getOutputStream();
os.write("from client:hello".getBytes());
//仅仅关闭数据流,并写一个结束标记,对socket没有影响
socket.shutdownOutput();
// InputStream is = socket.getInputStream();
// int b;
// while ((b=is.read())!=-1){
// System.out.println((char) b);
// }
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
os.close();
socket.close();
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket socket=new ServerSocket(9999);
Socket accept = socket.accept();
InputStream is = accept.getInputStream();
int b;
while ((b=is.read())!=-1){
System.out.print((char)b);
}
// OutputStream os=accept.getOutputStream();
// os.write("你谁啊".getBytes());
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("from 服务端:你谁啊");
bw.newLine();
bw.flush();
bw.close();
is.close();
accept.close();
socket.close();
}
}
4.2客户端与服务端传输文件
import java.io.*;
import java.net.Socket;
public class ClientDemo {
public static void main(String[] args) throws IOException {
Socket socket=new Socket("127.0.0.1",9999);
//本地流 用来读取本地文件
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("test\\clientfile\\41.jpg"));
//写到服务器 网络中的流
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos=new BufferedOutputStream(os);
int b;
while ((b=bis.read())!=-1){
bos.write(b);//通过网络写到服务器
}
//告诉服务器 文件传输完毕
socket.shutdownOutput();
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
socket.close();
bis.close();
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(9999);
Socket accept = socket.accept();
//网络中的流 从客户端读取数据
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
//本地的IO流,把数据写到本地中
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test\\serverfile\\copy41.jpg"));
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("from server:上传成功");
bw.newLine();
bw.flush();
bos.close();
accept.close();
socket.close();
}
}
四、服务端优化
1.服务端代码优化1
上面的文件传输代码的问题在于,服务端只能接受一次来自于客户端的传输就会关闭。因此需要改进,解决办法:使用死循环;
将服务端接受数据代码改为死循环,这样服务端一直可以接受数据
加上while(true)
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(9999);
while (true) {
Socket accept = socket.accept();
//网络中的流 从客户端读取数据
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
//本地的IO流,把数据写到本地中
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test\\serverfile\\copy412.jpg"));
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("from server:上传成功");
bw.newLine();
bw.flush();
bos.close();
accept.close();
}
//socket.close();
}
}
2.服务端代码优化2
while(true)也是有弊端的,继续改进
弊端:虽然可以让服务器处理多个客户端请求,但是无法同时请求多个客户端,解决办法:使用多线程
import java.io.*;
import java.net.Socket;
public class ClientDemo {
public static void main(String[] args) throws IOException {
Socket socket=new Socket("127.0.0.1",9999);
//本地流 用来读取本地文件
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("test\\clientfile\\1.jpg"));
//写到服务器 网络中的流
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos=new BufferedOutputStream(os);
int b;
while ((b=bis.read())!=-1){
bos.write(b);//通过网络写到服务器
}
//告诉服务器 文件传输完毕
socket.shutdownOutput();
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
socket.close();
bis.close();
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(9999);
while (true) {
Socket accept = socket.accept();
ThreadSocket ts=new ThreadSocket(accept);
new Thread(ts).start();
}
//socket.close();
}
}
import java.io.*;
import java.net.Socket;
import java.util.UUID;
public class ThreadSocket implements Runnable {
private Socket acceptSocket;
public ThreadSocket(Socket accept) {
this.acceptSocket = accept;
}
@Override
public void run() {
BufferedOutputStream bos = null;
try {
//网络中的流 从客户端读取数据
BufferedInputStream bis = new BufferedInputStream(acceptSocket.getInputStream());
//本地的IO流,把数据写到本地中
bos = new BufferedOutputStream(new FileOutputStream("test\\serverfile\\" + UUID.randomUUID().toString() + ".jpg"));
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(acceptSocket.getOutputStream()));
bw.write("from server:上传成功");
bw.newLine();
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bos!=null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (acceptSocket!=null){
try {
acceptSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.服务端代码优化3
当上述优化2中使用到了线程后又会引发新的问题,使用多线程虽然可以使得服务器同时处理多个客户端请求,但是资源消耗太大;解决办法 :使用线程池
import java.io.*;
import java.net.Socket;
public class ClientDemo {
public static void main(String[] args) throws IOException {
Socket socket=new Socket("127.0.0.1",9999);
//本地流 用来读取本地文件
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("test\\clientfile\\1.jpg"));
//写到服务器 网络中的流
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos=new BufferedOutputStream(os);
int b;
while ((b=bis.read())!=-1){
bos.write(b);//通过网络写到服务器
}
//告诉服务器 文件传输完毕
socket.shutdownOutput();
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
socket.close();
bis.close();
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(9999);
//使用线程池
ThreadPoolExecutor pool=new ThreadPoolExecutor(
3,//核心线程数量
10,//线程总数量
60,//临时线程空闲时间
TimeUnit.SECONDS,//临时线程空闲时间的单位
new ArrayBlockingQueue<>(5),//阻塞队列
Executors.defaultThreadFactory(),//创建线程方式
new ThreadPoolExecutor.AbortPolicy());//任务拒绝策略
while (true) {
Socket accept = socket.accept();
ThreadSocket ts=new ThreadSocket(accept);
pool.submit(ts);
}
//socket.close();
}
}
import java.io.*;
import java.net.Socket;
import java.util.UUID;
public class ThreadSocket implements Runnable {
private Socket acceptSocket;
public ThreadSocket(Socket accept) {
this.acceptSocket = accept;
}
@Override
public void run() {
BufferedOutputStream bos = null;
try {
//网络中的流 从客户端读取数据
BufferedInputStream bis = new BufferedInputStream(acceptSocket.getInputStream());
//本地的IO流,把数据写到本地中
bos = new BufferedOutputStream(new FileOutputStream("test\\serverfile\\" + UUID.randomUUID().toString() + ".jpg"));
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(acceptSocket.getOutputStream()));
bw.write("from server:上传成功");
bw.newLine();
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bos!=null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (acceptSocket!=null){
try {
acceptSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4.uuid类的使用
对上述传输文件的名字进行迭代
import java.util.UUID;
public class UuidDemo {
public static void main(String[] args) {
UUID uuid = UUID.randomUUID();
String replace = uuid.toString().replace("-", "");
System.out.println(replace);
}
}