写在前面:
视频是什么东西,有看文档精彩吗?
视频是什么东西,有看文档速度快吗?
视频是什么东西,有看文档效率高吗?
诸小亮:讲解了一些基础知识后,我们正是学习Socket
张小飞:Sokcet 是啥?
诸小亮:Socket:Java中为网络通信提供的一种机制,专业称:套接字
两个电脑进行通信时,数据在两个Sokcet之间通过IO传输
张小飞:具体该如何使用呢?
诸小亮:Java中使用 Sokcet 有两种方式——UDP和TCP
诸小亮:我们先看UDP
不需要建立连接,封装数据包,大小限制在64K以内
不可靠,安全性差,但速度快(就是发,对方是否接到,咱不管,比如:村里的喇叭)
张小飞:还是演示一下吧
诸小亮:没问题,首先是——接收端,看下面的代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* 接收端
*/
public class Receive {
public static void main(String[] args) throws IOException {
//1. 创建Socket,监听10000端口
DatagramSocket socket = new DatagramSocket(10000);
//2. 通过数据包接收数据
byte[] arr = new byte[1024];
//3. 创建 DatagramPacket 对象,用来接收数据
DatagramPacket packet = new DatagramPacket(arr, arr.length);
System.out.println("UDP接收端,准备接收数据。。。。。。");
//3.1 调用receive方法,如果收不到数据,程序会阻塞(也就是程序会停在这里,直到有数据)
socket.receive(packet);
//4. 通过DatagramPacket对象,解析收到的数据
String ip = packet.getAddress().getHostAddress();
int port = packet.getPort();
byte[] data = packet.getData();
//5. 转换成String
String msg = new String(data,0, packet.getLength());
System.out.println("发送者IP:" + ip);
System.out.println("发送者端口:" + port);
System.out.println("消息内容:" + msg);
//6. 关闭Socket
socket.close();
}
}
张小飞:有了接收端,想必还有发送端把
诸小亮:那是必须的,下面就是发送端的代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Send {
public static void main(String[] args) throws IOException {
//1. 创建Socket,监听5000端口
DatagramSocket sendSocket = new DatagramSocket(5000);
//如果不指定端口,会随机开启一个端口进行数据发送
// DatagramSocket sendSocket = new DatagramSocket();
//2. 通过数据包封装数据
String msg = "亚瑟提着大宝剑冲过来了";
byte[] data = msg.getBytes();
//需要ip和端口号
DatagramPacket packet = new DatagramPacket(data, 0, data.length,
InetAddress.getLocalHost(),10000);
//3. 发送数据
System.out.println("UDP发送端,发送数据。。。。");
sendSocket.send(packet);
//4. 关闭Socket
sendSocket.close();
}
}
诸小亮:先启动接收端,再启动发送端,结果:
诸小亮:其实使用 UDP 可以实现群聊的功能
张小飞:哦?怎么实现?
诸小亮:UDP模式下,可以在局域网中发送广播消息,局域网中的每个电脑都能收到消息
IP地址中每个网段都有自己的广播地址,本机IP:192.168.31.173
则 192.168.31 网段的广播地址是 192.168.31.255
张小飞:那,具体应该如何实现呢?
诸小亮:把上面的代码稍微改改就行了
因为 receive 方法会阻塞,所以可以把 socket.receive(packet); 放到 while 循环中,一直接收消息
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Receive {
public static void main(String[] args) throws IOException {
//1. 创建Socket,监听10000端口
DatagramSocket socket = new DatagramSocket(10000);
System.out.println("UDP接收端,准备接收数据。。。。。。");
while (true){
//2. 通过数据包接收数据
byte[] arr = new byte[1024];
DatagramPacket packet = new DatagramPacket(arr, arr.length);
//receive方法,如果收不到数据会阻塞,也就是程序会停在这里直到有数据
socket.receive(packet);
//3. 通过DatagramPacket对象,解析收到的数据
String ip = packet.getAddress().getHostAddress();
byte[] data = packet.getData();
//转换成String
String msg = new String(data,0, packet.getLength());
System.out.println(ip + ":" + msg);
}
//4. 一直运行接收消息,所以不再关闭Socket
// socket.close();
}
}
发送端,接收用户的输入,然后发送广播
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Send {
public static void main(String[] args) throws IOException {
//1. 创建Socket,监听5000端口
DatagramSocket sendSocket = new DatagramSocket(5000);
//2. 接收用户输入
System.out.println("开始接收用户输入。。。。。。");
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null){
byte[] buf = line.getBytes();
DatagramPacket dp =
new DatagramPacket(buf,buf.length,
InetAddress.getByName("192.168.31.255"),10000);
sendSocket.send(dp);
if("886".equals(line))
break;
}
//4. 关闭Socket
sendSocket.close();
}
}
张小飞:您不是说还有 TPC 通信吗?这个怎么用?
诸小亮:TPC通信就比UDP要麻烦一些了
需要两台电脑建立连接,形成数据通道,在连接中进行大数据量传输
因为必须建立连接,所以效率低,但安全性高,比如:打电话
张小飞:这么说,可以做一对一通信?
诸小亮:是的
诸小亮:TCP通信需要创建连接,分为客户端(Socket)、服务端(ServerSocket)
/**
* 客户端
*/
public static void main(String[] args) throws IOException {
//1. 创建Socket对象,指定目的IP和端口,用于创建连接
Socket socket = new Socket("127.0.0.1", 10000);
//2. 发送数据
System.out.println("客户端发送数据。。。。。。");
OutputStream out = socket.getOutputStream();
out.write("亚瑟提着大宝剑冲过来了".getBytes());
//3. 关闭Socket
socket.close();
}
张小飞:这也不麻烦啊,比 UDP 简单多了
诸小亮:客户端是很简单,麻烦的地方在服务端,比如:
/**
* 服务端
*/
public static void main(String[] args) throws IOException {
//1. 创建ServerSocket,指定监听10000端口
ServerSocket serverSocket = new ServerSocket(10000);
System.out.println("等待客户端连接。。。。。。");
//2. 获取Socket对象,如果能够获取到,说明连接成功
//注意:accept 方法会阻塞,直到有连接过来
Socket client = serverSocket.accept();
String ip = client.getInetAddress().getHostAddress();
int port = client.getPort();
System.out.println(ip + "--" + port + ":连接成功。。。。。。");
//3. 通过客户端的IO流,获取数据
InputStream in = client.getInputStream();
byte[] arr = new byte[1024];
int len = in.read(arr);
String msg = new String(arr,0,len);
System.out.println(msg);
//3.关闭资源
client.close();
serverSocket.close();
}
诸小亮:先运行服务端,再运行客户端,结果:
张小飞:上面的代码服务端只能被动的接收数据啊,能不能让它们互相通信?
诸小亮:满足你
/**
* 客户端
*/
public static void main(String[] args) throws IOException {
//1. 创建Socket对象,指定目的IP和端口
Socket socket = new Socket("127.0.0.1", 10000);
//2. 发送数据
System.out.println("客户端发送数据。。。。。。");
OutputStream out = socket.getOutputStream();
out.write("亚瑟提着大宝剑冲过来了".getBytes());
//3. 拿到InputStream,用于获取服务端返回的数据
InputStream in = socket.getInputStream();
byte[] arr = new byte[1024];
int len = in.read(arr);
String msg = new String(arr,0,len);
System.out.println("服务端返回:" + msg);
//4. 关闭Socket
socket.close();
}
/**
* 服务端
*/
public static void main(String[] args) throws IOException {
//1. 创建ServerSocket,指定监听10000端口
ServerSocket serverSocket = new ServerSocket(10000);
System.out.println("等待客户端连接。。。。。。");
//2. 获取Socket对象,能够获取到,说明连接成功,accept会阻塞,直到新的连接过来
Socket client = serverSocket.accept();
String ip = client.getInetAddress().getHostAddress();
int port = client.getPort();
System.out.println(ip + "--" + port + ":连接成功。。。。。。");
//通过客户端的IO流,获取数据
InputStream in = client.getInputStream();
byte[] arr = new byte[1024];
int len = in.read(arr);
String msg = new String(arr,0,len);
System.out.println(msg);
//3. 返回信息给客户端
System.out.println("服务端端发送数据。。。。。。");
OutputStream out = client.getOutputStream();
out.write("吕布大招断路。。。。".getBytes());
//4.关闭资源
client.close();
serverSocket.close();
}
先运行服务端,再运行客户端,结果:
张小飞:额。。。。,您这样确实是互相通信,不过,能不能做成QQ聊天那样子的?
诸小亮:也是可以的
import java.io.*;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
//1. 创建Socket对象,指定目的IP和端口
Socket socket = new Socket("127.0.0.1", 20000);
//开启一个守护线程,用于接收用户输入
receiveUserInput(socket);
//接收服务端发送的数据
InputStream in = socket.getInputStream();
while (true){
byte[] arr = new byte[1024];
int len = in.read(arr);
if(len == -1){//-1:表示结束
break;
}
String msg = new String(arr,0,len);
System.out.println("server:" + msg);
//如果Server 发送过来的是 886,跳出循环,结束通讯
if("886".equals(msg)){
break;
}
}
//4. 关闭Socket
socket.close();
}
private static void receiveUserInput(Socket socket) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try{
//2. 接收用户输入,发送给Server
System.out.println("开始接收用户输入。。。。。。");
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
OutputStream out = socket.getOutputStream();
String line = null;
while(true){
line = reader.readLine();
out.write(line.getBytes());
//如果输入886,跳出循环,结束通讯
if("886".equals(line))
break;
}
}catch (Exception e){
}
}
});
//设置为守护线程,主线程结束后,守护线程也结束
t.setDaemon(true);
t.start();
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//1. 创建ServerSocket,指定监听10000端口
ServerSocket serverSocket = new ServerSocket(20000);
//2. 获取客户端连接,能够获取到,说明连接成功,accept会阻塞,直到新的连接过来
System.out.println("等待客户端连接。。。。。。");
Socket client = serverSocket.accept();
String ip = client.getInetAddress().getHostAddress();
System.out.println(ip + " 连接成功。。。。。。");
//开启一个守护线程,用于接收用户输入
receiveUserInput(client);
//通过客户端的IO流,获取数据
InputStream in = client.getInputStream();
while (true){
byte[] arr = new byte[1024];
int len = in.read(arr);
if(len == -1){//-1表示结束
break;
}
String msg = new String(arr,0,len);
System.out.println("client:" + msg);
//如果客户端发送的是886,跳出循环,结束通讯
if("886".equals(msg)){
break;
}
}
//4.关闭资源
client.close();
serverSocket.close();
}
private static void receiveUserInput(Socket client) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try{
//2. 接收用户输入,发送给client
System.out.println("开始接收用户输入。。。。。。");
//接收用户输入
BufferedReader bufr = new BufferedReader(
new InputStreamReader(System.in));
String line = null;
//给客户端发送数据
OutputStream out = client.getOutputStream();
while(true){
line = bufr.readLine();
out.write(line.getBytes());
//如果给客户端发送的是886,跳出循环,结束通讯
if("886".equals(line))
break;
}
}catch (Exception e){
}
}
});
//设置为守护线程,主线程结束后,守护线程也结束
t.setDaemon(true);
t.start();
}
}
上面代码,客户端和服务端,分别在局域网中的不同机器上运行