前言
- 网络通信需要协议,我们了解一下今天的主角:
TCP(传输控制协议):通信双发需要建立连接,安全、可靠。有严格意义上的客户端、服务端
例如:打电话
UDP(用户数据包协议):不需要建立连接,不可靠。任何一个方都可以成为客户端、服务端
例如:发短信
-
网络通信还需要知道对方的端口号、IP
InetAddress封装了一系列static方法,可以获取主机信息.
此外,还有InetSocketAddress ,该类实现IP套接字地址(IP地址+端口号)
TCP
- 客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
//客户端
public class TcpClientDemo {
static Socket socket = null;
static OutputStream on = null;
public static void main(String[] args) {
try {
// 需要知道服务器端地址、端口号
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
int port = 5900;
// 创建一个socket连接
socket = new Socket(inetAddress,port);
// 获取输出流
on = socket.getOutputStream();
on.write("你好,欢迎使用TCP连接".getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
if(on!=null){
try {
on.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
- 服务端
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class TcpServerDemo {
static ServerSocket server = null;
static Socket socket = null;
static InputStream in = null;
static ByteArrayOutputStream out = null;
public static void main(String[] args) {
try {
// 服务器需要一个地址
server = new ServerSocket(5900);
// 等待客户端连接(阻塞等待)
socket = server.accept();
// 读取客户端信息
in = socket.getInputStream();
// 管道字节流
out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
System.out.println(out.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (server != null) {
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注意:这里建议养成好的习惯,关闭资源,要写代码注释
实现文件上传
客户端上传文件给服务器端,服务器端收到文件后通知客户端并断开连接
- 服务端
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServerDemo {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(7800);
// 监听客户端的连接(阻塞式)
Socket socket = server.accept();
InputStream inputStream = socket.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(new File("recever.png"));
byte[] buff = new byte[1024];
int len;
while ((len = inputStream.read(buff))!=-1){
fileOutputStream.write(buff,0,len);
}
// 通知客户端我接收完毕
OutputStream os = socket.getOutputStream();
os.write("文件已接收,你可以断开连接了!".getBytes());
os.close();
fileOutputStream.close();
inputStream.close();
socket.close();
server.close();
}
}
- 客户端
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClientDemo {
public static void main(String[] args) throws Exception {
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),7800);
OutputStream out = socket.getOutputStream();
// 读取文件
FileInputStream fileInputStream = new FileInputStream(new File("timg.jpeg"));
// 写入文件
byte[] buff = new byte[1024];
int len;
while((len=fileInputStream.read(buff))!=-1){
out.write(buff,0,len);
}
// 通知服务器,文件传输完毕,断开连接
socket.shutdownOutput();
// 确定服务器已收到,断开连接
InputStream is = socket.getInputStream();
// 通过管道流接收服务端信息
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int le;
while((le=is.read(b))!=-1){
baos.write(b,0,le);
}
System.out.println(baos.toString());
baos.close();
is.close();
fileInputStream.close();
out.close();
socket.close();
}
}
ByteArrayOutputStream 字节数组输出流,这里用到是相当一个管道,避免出现中文乱码现象。
UDP
- DatagramSocket :是用于发送和接收数据。
- DatagramPacket :打包数据
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
构造用于发送长度的分组数据报包 length具有偏移 ioffset指定主机上到指定的端口号。
import java.net.*;
public class Udp1Demo {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(5050,InetAddress.getByName("localhost"));
String msg ="UDP无连接发信息";
DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,InetAddress.getByName("localhost"),4040);
socket.send(packet);
socket.close();
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Udp2Demo {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(5050);
byte[] bytes = new byte[1025];
DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length);
socket.receive(packet);
System.out.println(packet.getData());
socket.close();
}
}
多线程聊天
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class TalkReceive implements Runnable {
DatagramSocket socket =null;
private int fromPort;
private String msgFrom;
public TalkReceive(int fromPort,String msgFrom) {
this.fromPort = fromPort;
this.msgFrom = msgFrom;
try {
socket = new DatagramSocket(fromPort);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
byte[] b = new byte[1024];
DatagramPacket packet = new DatagramPacket(b,0,b.length);
socket.receive(packet);
String str = new String(packet.getData(),0,packet.getLength());
System.out.print(msgFrom+" : "+str);
if(str.equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
public class TalkSender implements Runnable {
DatagramSocket socket =null;
BufferedReader scan =null;
private int fromPort;
private String toIp;
private int toPort;
public TalkSender(int fromPort, String toIp, int toPort) {
this.fromPort = fromPort;
this.toIp = toIp;
this.toPort = toPort;
try {
socket = new DatagramSocket(fromPort, InetAddress.getByName(toIp));
scan = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
try {
String msg = scan.readLine();
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, InetAddress.getByName(toIp), toPort);
socket.send(packet);
if (msg.equals("bye"))
break;
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
public class TalkStudent {
public static void main(String[] args) {
new Thread(new TalkSender(5555,"localhost",9999)).start();
new Thread(new TalkReceive(7777,"老师")).start();
}
}
public class TalkTeacher {
public static void main(String[] args) {
new Thread(new TalkSender(3333,"localhost",7777)).start();
new Thread(new TalkReceive(9999,"学生")).start();
}
}
到此,就可以聊天了。UDP相比较TCP更加简单,他不需要建立连接。
URL(统一资源定位符)
- 顾名思义,是用来定位资源的嘛~
- 组成: 协议://IP地址:端口号/项目名
例如:https://www.baidu.com/baidu,这里隐藏了端口号
下载资源
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class Down {
public static void main(String[] args) throws Exception {
URL url = new URL("https://m10.music.126.net/20200822185011/f80542d39dd545f8c5238742801049ab/yyaac/obj/wonDkMOGw6XDiTHCmMOi/2180584755/addb/4c39/1202/a7e369ca61357fc66eab2467a823d356.m4a");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream in = connection.getInputStream();
FileOutputStream out = new FileOutputStream(new File("夏天的风.m4a"));
byte[] buff = new byte[1024];
int len;
while ((len=in.read(buff))!=-1){
out.write(buff,0,len);
}
out.close();
in.close();
connection.disconnect();
}
}
下载成功莫名的激动,以后下资源。。嘿嘿。
希望这里对大家有所帮助,谢谢~~
依然有困惑的,可以搜索 blibli up主 遇见狂神说,看看它讲的这一节,非常的nice