【达内课程】Socket编程基础

介绍

【什么是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。
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值