JAVA网络编程
1.网络
1.1计算机网络
计算机网络:分布在不同地理位置上的计算机,通过专用的线路和设备连在一起,可以共享硬件、软件、数据。
1.2网络编程
网络编程:就是使用计算机语言编写可以在互联网上相互通信的软件。
1.3 IP地址
IP规定了计算机在网络中的地址,一台计算机只有符合IP才可以连接到互联网上,和其他计算机相互通信。IP地址是互联网中其他电脑找到你这台电脑的唯一依据。
2.传输协议
2.1 TCP
TCP:传输控制协议,面向连接,安全、可靠。缺点:速度慢。例如:打电话
2.2 UDP(用户数据报协议)
发电报、发短信(面向无连接,不安全,不可靠),有点:速度快。
3.JAVA网络编程
java网络编程采用的是套接字(Socket)编程模型。无论是 TCP 还是 UDP 协议都采用统一的套接字编程。
TCP程序要先启动服务器程序,然后才是客户端程序。
UDP必须先启动客户端,然后才是服务器。
4.Code Demo
4.1 服务端与客户端建立通信连接
(1)客户端
点击查看代码
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ClientSocket {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
//创建客户端套接字,用于交互服务端 指定服务器ip + 端口号
Socket socket = new Socket("127.0.0.1", 9999);
//根据套接字获取输出流
OutputStream outputStream = socket.getOutputStream();
//将字节输出流包装成 数据字节输出流|特殊流
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF("hello 服务器!");
dataOutputStream.flush();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
(2)服务端
点击查看代码
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocket {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
//创建ServerSocket(服务端套接字) 并指定端口号,不需要指定ip
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("---------服务端暴露成功----9999---");
//通过服务端套接字 监听客户端的连接,如果没有客户端连接,那么程序会一直停留在此处,accept方法的返回值就是 客户端的套接字,通过该套接字可以与客户端交互
Socket socket = serverSocket.accept();
//根据客户端套接字,获取对应的输入流,通过此输入流就能拿到客户端发送过来的信息
InputStream inputStream = socket.getInputStream();
//将输入字节流包装成特殊数据处理流
DataInputStream dataInputStream = new DataInputStream(inputStream);
System.out.println(dataInputStream.readUTF());
System.out.println("--------程序执行完毕---------");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
4.2 服务端与客户端连续通信(来回发送)
(1)客户端
点击查看代码
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* Version:1.0
* 1、客户端不断发送信息给服务端,并且获取服务端发送的信息
* 2、一个客户端,一个服务端
*/
public class ClientSocket {
//定义Scanner用户获取输入的信息
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
try {
//创建客户端套接字
Socket socket = new Socket("127.0.0.1", 9999);
while (true) {
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//创建数据字节输出流
dataOutputStream.writeUTF("客户端:" + scanner.next());
//获取服务端发送的信息
String message = dataInputStream.readUTF();
System.out.println(message);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
(2)服务端
点击查看代码
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* Version:1.0
* 1、服务端可以不断获取客户端发送的信息,并且发送信息给客户端
* 2、一个客户端,一个服务端
*/
public class ServerSocket{
//定义Scanner用户获取输入的信息
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
try {
//创建服务端套接字
ServerSocket serverSocket = new ServerSocket(9999);
//获取客户端套接字|请求
Socket socket = serverSocket.accept();
while (true) {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//获取客户端发送的信息
String message = dataInputStream.readUTF();
System.out.println(message);
//服务端继续给客户端发送信息
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("服务端:" + scanner.next());
dataOutputStream.flush();
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
注:以上通信只能实现客户端与服务端轮流发送消息,客户端发送消息之后需要等待服务端响应之后才能继续发送消息,否则客户端一直处于阻塞状态,无法实现客户端与服务端独立发送消息和接收消息。要想实现客户端与服务端独立收发消息,则需要实现收、发分离。
4.3 客户端与服务端独立收、发消息
(1)客户端
点击查看代码
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* Version:1.0
* 1、客户端不断发送信息给服务端,并且获取服务端发送的信息
* 2、一个客户端,一个服务端
*/
public class ClientSocket {
//定义Scanner用户获取输入的信息
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
try {
//创建客户端套接字
Socket socket = new Socket("127.0.0.1", 9999);
//开启线程用于读取服务器发送的信息
new ThreadClient(socket).start();
while (true) {
//发送信息至服务器
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
//创建数据字节输出流
dataOutputStream.writeUTF("客户端:" + scanner.next());
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
class ThreadClient extends Thread {
private Socket socket;
public ThreadClient() {
}
public ThreadClient(Socket socket) {
this.socket = socket;
}
//重写Thread类的run方法,在该方法中负责读取服务器发送的信息
@Override
public void run() {
try {
while (true) {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//获取服务端发送的信息
String message = dataInputStream.readUTF();
System.out.println(message);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
(2)服务端
点击查看代码
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* Version:1.0
* 1、服务端可以不断获取客户端发送的信息,并且发送信息给客户端
* 2、一个客户端,一个服务端
*/
public class ServerSocketTest {
public static void main(String[] args) {
try {
//创建服务端套接字
ServerSocket serverSocket = new ServerSocket(9999);
//获取客户端套接字|请求
Socket socket = serverSocket.accept();
//开启线程用户发送信息给客户端
new ThreadServer(socket).start();
while (true) {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//获取客户端发送的信息
String message = dataInputStream.readUTF();
System.out.println(message);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
class ThreadServer extends Thread {
//定义Scanner用户获取输入的信息
private static Scanner scanner = new Scanner(System.in);
private Socket socket;
public ThreadServer() {
}
public ThreadServer(Socket socket) {
this.socket = socket;
}
//重写Thread类的run方法,在该方法中负责读取服务器发送的信息
@Override
public void run() {
try {
while (true) {
//服务端继续给客户端发送信息
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("服务端:" + scanner.next());
dataOutputStream.flush();
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
4.4 多个客户端、一个服务端
(1)客户端1
点击查看代码
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* Version:1.0
* 1、客户端不断发送信息给服务端,并且获取服务端发送的信息
* 2、多个客户端,一个服务端
*/
public class SocketTest {
//定义Scanner用户获取输入的信息
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
try {
//创建客户端套接字
Socket socket = new Socket("10.74.69.10", 9999);
//开启线程用于读取服务器发送的信息
new ThreadClient(socket).start();
while (true) {
//发送信息至服务器
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
//创建数据字节输出流
dataOutputStream.writeUTF("客户端A:" + scanner.next());
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
class ThreadClient extends Thread {
private Socket socket;
public ThreadClient() {
}
public ThreadClient(Socket socket) {
this.socket = socket;
}
//重写Thread类的run方法,在该方法中负责读取服务器发送的信息
@Override
public void run() {
try {
while (true) {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//获取服务端发送的信息
String message = dataInputStream.readUTF();
System.out.println(message);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
(2)客户端2
点击查看代码
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* Version:1.0
* 1、客户端不断发送信息给服务端,并且获取服务端发送的信息
* 2、多个客户端,一个服务端
*/
public class SocketTest2 {
//定义Scanner用户获取输入的信息
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
try {
//创建客户端套接字
Socket socket = new Socket("10.74.69.10", 9999);
//开启线程用于读取服务器发送的信息
new ThreadClient2(socket).start();
while (true) {
//发送信息至服务器
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
//创建数据字节输出流
dataOutputStream.writeUTF("客户端B:" + scanner.next());
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
class ThreadClient2 extends Thread {
private Socket socket;
public ThreadClient2() {
}
public ThreadClient2(Socket socket) {
this.socket = socket;
}
//重写Thread类的run方法,在该方法中负责读取服务器发送的信息
@Override
public void run() {
try {
while (true) {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//获取服务端发送的信息
String message = dataInputStream.readUTF();
System.out.println(message);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
(3)服务端
点击查看代码
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/**
* Version:1.0
* 1、服务端可以不断获取客户端发送的信息,并且发送信息给客户端
* 2、多个客户端,一个服务端
*/
public class ServerSocketTest {
//定义集合用于存储所有的客户端Socket套接字
public final static List<Socket> socketList = new ArrayList<>();
public static void main(String[] args) {
try {
//创建服务端套接字
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("-----------服务端暴露成功-------");
while (true) {
//获取客户端套接字|请求,因为我们的服务端可以监听N个客户端,因此 将 serverSocket.accept() 放在循环中
Socket socket = serverSocket.accept();
System.out.println("socket:" + socket);
//将客户端 Socket存放在 集合中
socketList.add(socket);
System.out.println("当前在线人数:" + socketList.size());
//开启线程用户发送信息给客户端
new ThreadServer(socket).start();
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
class ThreadServer extends Thread {
private Socket socket;
public ThreadServer() {
}
public ThreadServer(Socket socket) {
this.socket = socket;
}
//重写Thread类的run方法,在该方法中负责读取服务器发送的信息
@Override
public void run() {
try {
while (true) {
//获取客户端发送的信息
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
String message = dataInputStream.readUTF();
//将信息广播给每一个客户端
for (int i = 0; i < ServerSocketTest.socketList.size(); i++) {
Socket socket = ServerSocketTest.socketList.get(i);
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(message);
//刷新
dataOutputStream.flush();
}
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}