介绍
【什么是IP地址】
处于网络中的每一个终端机器都分配一个 IP 地址。
0.0.0.0 ~ 255.255.255.255
我们如果需要访问别人的机器,必须获取别人机器的 IP 地址
【什么是端口号】
每一个服务端程序在开启服务时,都需要通知操作系统开辟一个未被占用的端口号。
客户端在访问服务端程序时,不仅需要 IP 地址,还需要端口号。
【什么是Socket(套接字)】
Socket 就是 Java 中的一个类。
封装了客户端服务端通信过程中涉及到的 IP 地址、端口号等属性,还封装了客户端与服务端建立连接的方法 connect()
服务端和客户端连接
Server.java
/**
* 服务端
*/
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
//阻塞执行 接受客户端的连接请求
System.out.println("服务端已启动...");
Socket socket = ss.accept();
System.out.println("客户端进来了" + socket.getInetAddress());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
//代表本机
/*String ip = "localhost";
String ip = "192.168.137.1";*/
String ip = "127.0.0.1";
try {
//自动建立链接
Socket socket = new Socket(ip, 8888);
System.out.println("客户端连接成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
【查看IP地址方法】
client 中的 ip 地址以下两种方式都代表本机:
String ip = "localhost";
String ip = "127.0.0.1";
先运行 Server.java,然后运行 Client.java
服务端和客户端对话
Server.java
/**
* 服务端
*/
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
//阻塞执行 接受客户端的连接请求
System.out.println("服务端已启动...");
Socket socket = ss.accept();
System.out.println("客户端进来了" + socket.getInetAddress());
//获取输出流
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF("请问您来点什么?");
dos.flush();
//接收请求
DataInputStream dis = new DataInputStream(socket.getInputStream());
String recept = dis.readUTF();
dos.writeUTF("对不起,没有" + recept);
dos.flush();
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
String ip = "localhost";
try {
//自动建立链接
Socket socket = new Socket(ip, 8888);
System.out.println("客户端连接成功");
//读取服务端写过来的字符串
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
String text = dis.readUTF();
System.out.println("Server:" + text);
//在控制台接受客户端的参数
Scanner console = new Scanner(System.in);
String line = console.nextLine();
//输出给服务端
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(line);
dos.flush();
//读取服务端的回应
text = dis.readUTF();
System.out.println("Server:" + text);
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
让服务端和客户端一直聊天
Server.java
/**
* 服务端
*/
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
//阻塞执行 接受客户端的连接请求
System.out.println("服务端已启动...");
Socket socket = ss.accept();
System.out.println("客户端进来了" + socket.getInetAddress());
//获取输出流
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF("请问您来点什么?");
dos.flush();
//接收请求
DataInputStream dis = new DataInputStream(socket.getInputStream());
while (true) {
String recept = dis.readUTF();
if (recept.equals("不吃了")) {
break;
}
dos.writeUTF("对不起,没有" + recept + ",换一个?");
dos.flush();
}
dos.writeUTF("一路走好");
dos.flush();
dos.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
String ip = "localhost";
try {
//自动建立链接
Socket socket = new Socket(ip, 8888);
System.out.println("客户端连接成功");
//读取服务端写过来的字符串
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
String text = dis.readUTF();
System.out.println("Server:" + text);
//在控制台接受客户端的参数
Scanner console = new Scanner(System.in);
while (true) {
String line = console.nextLine();
//输出给服务端
dos.writeUTF(line);
dos.flush();
//读取服务端的回应
text = dis.readUTF();
System.out.println("Server:" + text);
if (text.equals("一路走好")) {
break;
}
}
dos.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
优化
.accept()
方法是阻塞执行的,阻塞,然后等待连接,一旦有客户端过来连接,那么这句代码就可以接着向下执行。
如果没有客户端连接,那么会一直阻塞。
现在,我想让一个人连完之后再执行accept()
接着连接第二个人,可以在外边加一个while(true)
来一直执行:
/**
* 服务端
*/
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
//阻塞执行 接受客户端的连接请求
System.out.println("服务端已启动...");
while(true){
Socket socket = ss.accept();
......
socket.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
实现服务端“同时”处理多个客户端的连接架构:
main{
ServerSocket ss = new ......;
while(){
Socket socket = ss.accept();
new WorkThread(socket).start();
}
class WorkThread extends Thread{
private Socket socket;
public WorkThread(Socket socket){
this.socket = socket;
}
run(){
与客户端交互
socket.getInputStream()
}
}
}
按照以上思路修改Server.java
/**
* 服务端
*/
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
//阻塞执行 接受客户端的连接请求
System.out.println("服务端已启动...");
while (true) {
Socket socket = ss.accept();
System.out.println("客户端进来了" + socket.getInetAddress());
//启动工作线程
new WorkThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 处理客户端交互的工作线程
*/
static class WorkThread extends Thread {
private Socket socket;
public WorkThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//获取输出流
try {
//获取输出流
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF("请问您来点什么?");
dos.flush();
//接收请求
DataInputStream dis = new DataInputStream(socket.getInputStream());
while (true) {
String recept = dis.readUTF();
if (recept.equals("不吃了")) {
break;
}
dos.writeUTF("对不起,没有" + recept + ",换一个?");
dos.flush();
}
dos.writeUTF("一路走好");
dos.flush();
dos.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
先运行 Server,然后分别运行 Client 1 和 2。