网络编程
概念
实现多台计算机之间实现数据的共享和传递,网络应用程序主要组成为:网络编程+IO流+多线程
网络编程3要素
网络通讯的模型:请求-响应,客户端-服务端
三要素:IP地址,端口,协议(数据传输的规则)
- IP地址:网络中计算机的唯一标识
- IP地址的组成:网络号段 + 主机段
- 一个IP可以对应多个域名,但是一个域名在一个时刻只能对应一个IP
- 端口号:应用程序的标识
- 有效端口:065535,其中01024系统使用或保留端口。
- 端口与协议有关:TCP和UDP的端口互不相干,同一个协议的端口不能重复,不同协议的可以重复
- 协议:通信规则,就是数据的传输规则
InetAddress 类
用来表示主机的信息
- 静态方法:getByName();
- 在给定主机名的情况下确定主机的 IP 地址。
- 静态方法:getLocalHost();
- 返回本地主机的 IP。
Socket
Scoket也叫套接字,其表示的是IP地址和端口号的组合。
网络编程主要就是指Socket编程,网络间的通信其实就是Socket间的通信,数据就通过IO流在两个Scoket间进行传递。
TCP 编程
1、一对一聊天
API:Socket,ServerSocket
客户端(发送一个请求), 服务端(接收到这个请求,给予响应)
客户端
public class Client {
@SuppressWarnings("all")
public static void main(String[] args) throws IOException {
Socket socket = new Socket("10.7.173.81",8080);//参数:IP和端口号
//1.向服务端发送消息
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("123");
ps.println("123");
ps.println("123");
//4.接收来自服务端的消息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String string = br.readLine();
System.out.println(string);
}
}
服务端
public class Server {
@SuppressWarnings("all")
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept();
//2.接收来自客户端的消息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String string = br.readLine();
System.out.println(string);
//3.向客户端发送消息
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("404!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2、优化一对一聊天
客户端
public class Client {
@SuppressWarnings("all")
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("10.7.173.81",8080);
Scanner sc = new Scanner(System.in);
//接收消息
new ReceiveThread(socket).start();
//发送消息
PrintStream ps = new PrintStream(socket.getOutputStream());
while(true){
ps.println("Client:" + sc.next());
}
}
}
服务端
public class Server {
@SuppressWarnings("all")
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept();
new ReceiveThread(socket).start();
//发送消息
Scanner sc = new Scanner(System.in);
PrintStream ps = new PrintStream(socket.getOutputStream());
while(true){
ps.println("Server:" + sc.next());
}
}
}
接收信息的线程类
public class ReceiveThread extends Thread{
private Socket socket;
public ReceiveThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
while(true){
String string = null;
try {
string = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(string);
}
}
}
3、传输文件
客户端
public class Client {
/**
* 需求:传输文件
*/
@SuppressWarnings("all")
public static void main(String[] args) throws UnknownHostException, IOException{
Socket socket = new Socket("127.0.0.1", 8080);
FileInputStream in = new FileInputStream("学习.mp4");
OutputStream out = socket.getOutputStream();
byte[] bs = new byte[1024];
int len;
while((len = in.read(bs)) != -1){
out.write(bs, 0, len);
}
in.close();
out.close();
}
}
服务端
public class Server {
@SuppressWarnings("all")
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept();
InputStream in = socket.getInputStream();
FileOutputStream out = new FileOutputStream("download.mp4");
byte[] bs = new byte[1024];
int len;
while((len = in.read(bs)) != -1){
out.write(bs, 0, len);
}
in.close();
out.close();
}
}
4、群聊功能
客户端
public class Client {
/**
* 需求:群聊
*/
@SuppressWarnings("all")
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 8080);
Scanner scan = new Scanner(System.in);
new ReceiveThread(socket).start();
PrintStream ps = new PrintStream(socket.getOutputStream());
while(true){
ps.println("林成:" + scan.next());
}
}
}
服务端
public class Server {
public static ConcurrentHashMap<InetAddress, Socket> map = new ConcurrentHashMap<>();
@SuppressWarnings("all")
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8080);
while(true){
Socket socket = server.accept();
//获取客户端的IP地址
InetAddress ip = socket.getInetAddress();
//存IP和Socket
map.put(ip,socket);
//创建线程
new ServerThread(socket).start();
}
}
}
接收信息的线程
public class ReceiveThread extends Thread{
private Socket socket;
public ReceiveThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e1) {
e1.printStackTrace();
}
while(true){
String readLine = null;
try {
readLine = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(readLine);
}
}
}
发送信息的线程
public class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//接收当前Socket的消息
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e1) {
e1.printStackTrace();
}
while(true){
String readLine = null;
try {
readLine = br.readLine();
System.out.println(readLine);
//发送给其他Socket
ConcurrentHashMap<InetAddress,Socket> map = Server.map;
Set<Entry<InetAddress,Socket>> entrySet = map.entrySet();
for (Entry<InetAddress, Socket> entry : entrySet) {
InetAddress key = entry.getKey();
Socket value = entry.getValue();
if(socket.getInetAddress() != key){
PrintStream ps = new PrintStream(value.getOutputStream());
ps.println(readLine);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
UDP 编程
概念:用户数据报包协议,UDP和TCP位于同一层-传输层,但它对于数据包的顺序错误或重发没有TCP可靠;UDP是一种面向无连接的通信协议。UDP向应用程序提供一种发送封装的原始IP数据报的方法,并且发送时无需建立连接,不保证可靠数据的传输
UDP - - 发短信
TCP - - 打电话
所需要的类
DatagramPacket — 此类表示数据报包
DatagramSocket — 此类用来发送和接受数据报包的套接字
getLocalSocketAddress(); 返回此套接字绑定的端点的地址,如果尚未绑定则返回 null。
send(DatagramPacket p); 从此套接字发送数据报包。
receive(DatagramPacket p); 从此套接字接收数据报包。
SocketAddress — 抽象类,表示 IP+端口号 的组合
1、一对一聊天
客户端1
public class Client01 {
public static void main(String[] args) throws IOException {
/**
* 知识点:UDP协议
*/
//1号所在城市的快递公司
DatagramSocket socket = new DatagramSocket();
//1.1号发快递
byte[] bs = "1号,我发礼物过来了!!".getBytes();
DatagramPacket packet = new DatagramPacket(bs, bs.length,InetAddress.getByName("127.0.0.1"),8080);
socket.send(packet);
//4.接收2号的回礼
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
System.out.println(new String(buf).trim());
}
}
客户端2
public class Client02 {
public static void main(String[] args) throws IOException {
/**
* 知识点:UDP协议
*/
//2号所在城市的快递公司
DatagramSocket socket = new DatagramSocket(8080);
//2.接收1号的礼物
byte[] bs = new byte[1024];
DatagramPacket packet = new DatagramPacket(bs, bs.length);
socket.receive(packet);
System.out.println(new String(bs).trim());
//3.给1号回礼
byte[] buf = "我收到礼物了,这是回礼~~".getBytes();
packet = new DatagramPacket(buf, buf.length,packet.getSocketAddress());
socket.send(packet);
}
}
2、优化一对一聊天
客户端1
public class Client01 {
public static void main(String[] args) throws SocketException {
/**
* 知识点:一对一聊天
*/
DatagramSocket socket = new DatagramSocket(7070);
new SendThread(socket, "1号", "127.0.0.1", 8081).start();
new ReceiveThread(socket).start();
}
}
客户端2
public class Client02 {
public static void main(String[] args) throws SocketException {
/**
* 知识点:一对一聊天
*/
DatagramSocket socket = new DatagramSocket(8081);
new SendThread(socket, "2号", "127.0.0.1", 7070).start();
new ReceiveThread(socket).start();
}
}
接收信息的线程类
public class ReceiveThread extends Thread{
private DatagramSocket socket;
public ReceiveThread(DatagramSocket socket) {
this.socket = socket;
}
@Override
public void run() {
while(true){
byte[] bs = new byte[1024];
DatagramPacket packet = new DatagramPacket(bs,bs.length);
try {
socket.receive(packet);
System.out.println(new String(bs).trim());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
发送信息的线程类
public class SendThread extends Thread{
private DatagramSocket socket;
private String name;
private String ip;
private int port;
public SendThread(DatagramSocket socket, String name, String ip, int port) {
this.socket = socket;
this.name = name;
this.ip = ip;
this.port = port;
}
@Override
public void run() {
Scanner sc = new Scanner(System.in);
while(true){
byte[] bs = (name + ":" + sc.next()).getBytes();
DatagramPacket packet;
try {
packet = new DatagramPacket(bs, bs.length,InetAddress.getByName(ip),port);
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}