第十九节 Socket网络编程

Socket

1.概述

  1. Socket 编程又叫 套接字编程

    • 套接字,即使用TCP提供了两台计算机之间的通信机制 。
  2. 怎么通讯的呢!? 客户端程序 创建一个套接字,并尝试连接 服务器 的套接字。当连接建立时,服务器会创建一个Socket对象。客户端和服务器现在可以通过对Socket对象的 写入和读取(I/O) 来进行通信。(简单理解为,两边都要有socket,都通过socket进行通信)。

    • Socket 简单理解: 网络编程相当于 Ip地址与端口和协议(底层很多种,泛指Tcp,ip)的组合。 使其多台计算机在通过socket进行通信。
  3. 举一个例子:

    • 应用程序,如QQ,它产生的聊天数据是通过这样的Tcp/ip协议进行传输的,但是QQ 不会 直接和传输协议建立联系,而是能把应用程序和传输协议之间连接起来的桥梁,这个桥梁就是所谓的socket
    1. 查看套接字的命令:
    		 netstat 是用于显示套接字内容的命令,-ano 选项表示以下的意思:
    			a:不仅显示正在通信的套接字,还显示包括尚未开始通信等状态的所有套接字
    			n:显示 IP 地址和端口号
    			o:显示使用该套接字的程序 PID
    2.注意:端口号有 0~65535  其中0-1024是被占用的。
    

在这里插入图片描述

其中第4和5说明:
4.状态:
State,表示通信状态。
	LISTENING:等待对方连接的状态
	ESTABLISHED:完成连接并正在进行数据通信的 状态
	CLOSE WAIT:表示被动关闭
	SYN_SENT:是三次握手的过程,表示你的机器发 起了连接,对方没有响应
	TIME WAIT:等待足够的时间以确保远程 TCP 接收到连接中断请求的确认
5.pid:进程的标识符。

2. 服务器

2.1 ServerSocket

  1. java.net.ServerSocket 服务器端需要的类,在服务器端开启一个端口号,然后侦听客户端的请求。

    1.构造方法:
    	ServerSocket(int port) 
    		创建绑定到指定端口的服务器套接字。 
    2.常用方法:
    	Socket   accept() 
    		侦听要连接到此套接字并接受它。 
    	void close()  
    		关闭套接字。
    3.操作:启动服务。
    	ServerSocket ss = new ServerSocket(端口号);
          等待客户端发起连接,连接后会建立起通道:Socket socket = ss.accept(); 侦听
    

3. 客户端

3.1 Socket

  1. java.net.Socket类代表客户端和服务器都用来互相沟通的套接字,并通过io流操作。

    • 客户端要通过实例化获取一个Socket对象,而服务器则通过accept方法的返回值获得一个Socket对象。
    1.构造方法:
         Socket(String host,int port) 
         	创建一个流套接字,并将其连接到指定主机上的指定端口号。
    2.常用方法:
    	InputStream getInputStream() 
    		返回此套接字的输入流。
    	OutputStream getOutputStream() 
    		返回此套接字的输出流。
    	void close() 
    		关闭此套接字。
    		
    3. 操作:新建Socket对象,连接指定IP指定的端口。
    	   Socket s = new Socket(IP,port);Socket获取双向的流:
    	InputStream in = s.getInputStream();
    	OutputStream out = s.getOutputStream();
    

4. 入门案例

在这里插入图片描述

4.1 服务器端创建

  • 接受客户端发来得数据,并服务端响应返回数据。
  • 注意启动顺序:先启动 Server 在启动 Client
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/*1.创建服务器端,用来接受客户端请求。
 - 启动服务器。
 - 开始监听客户端。
 */
public class Test_Server {
    public static void main(String[] args) throws Exception{
        //1.创建服务器 ,
        ServerSocket server = new ServerSocket(8200);//端口号选择需要注意。0-1024被占用.
        //2.接受
        Socket socket = server.accept(); //监听客户端请求。
        //3.接受客户端请求数据
        InputStream in = socket.getInputStream();
        //3.1 输出结果。
        int b;
        for (int i = 0; i <5 ; i++) {
            System.out.println((char)(b=in.read()));//字节转换字符
        }

        //4.给客户端返回信息
        OutputStream out = socket.getOutputStream();
        out.write("world".getBytes());


        out.flush();
        server.close();
    }
}

4.2 客户端创建

  • 注意关流顺序,如果提前关闭会报错Socket is closed
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/*  1.创建客户端,需要指定连接的服务器
    2.给服务器发送数据
 */
public class Test_Client {
    public static void main(String[] args) throws Exception{

        //1.创建客户端
        Socket socket = new Socket("127.0.0.1",8200);
        //2.向服务器发送数据,先获取输出流。
        OutputStream out = socket.getOutputStream();
        //out.write("你好".getBytes()); //需要转码
        out.write("hello".getBytes());

         //3关闭资源
         //out.close(); //由于提前关闭资源,Socket is closed 报错
         out.flush();


         //4接受服务器返回的数据
        InputStream in = socket.getInputStream();
        int b ;
        for (int i = 0; i <5 ; i++) {
            System.out.println((char)(b=in.read())); //字节转换字符
        }

        socket.close();
    }
}

5. 案例: Socket 回声案例

  • 场景: 需要服务器创建多个连接。 如同: 生活中,给客服中心打电话,每一个客户会对应一个客户(相当于只有一个客户中心,会分配多个客户人员去解决客户端问题)。
  • 客户端发送数据,客服回复数据。

5.1 服务器端

  • 重点在服务器端开发,需要注意如何处理多个客户端请求问题。
  • 如何分配“客服”解决每个客户端的io问题。
/**
 *       1.启动服务器
 *       2.连接客户端
 *       3.创建服务器的话务员,给每一个客户端配一个"客服";
 *            作用: 客服负责和客户端的io连接。
 */
public class Server {
    public static void main(String[] args) {
        //启动服务
        new Server().service();
    }

    //创建方法,负责多个客户端。123的处理。
     public void service(){
            //内部类,主要负责客户端的监听。
            class MyThread extends Thread{
                @Override
                public void run() {
                    try {
                        //启动服务器
                        ServerSocket serverSocket = new ServerSocket(8200);
                        System.out.println("启动服务器成功");
                        //1.如果是多客户端连接,就需要多个监听
                        //Socket socket = serverSocket.accept();
                        while (true){//通过循环拿到多个连接监听
                            Socket socket = serverSocket.accept();
                            System.out.println("连接客户端成功");
                            //2.分配"每一个客户端多应的客服",多线程。
                            FuWuThread t = new FuWuThread(socket);
                            t.start();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            //2.1 注意:启动客服服务
            new MyThread().start();
     }

     //3.创建内部类“客服”。作用负责io的沟通。(只为Server服务)
     class FuWuThread extends Thread{
       //3.1 将所有数据保存在socket上,获取流(负责读写),但是如何获取Socket!?
         Socket socket;
         //通过含参数构造方法;
         public FuWuThread(Socket socket){
             this.socket=socket;
         }

         //4.重写run()并接受客户端传来得数据。
         @Override
         public void run() {
             //改造一下使用高效包装,通过转换流 InputStreamReader 把字节转换为字符。
             try {
                 //socket编程中一定要用printWriter去写。不能使用BufferWirter。
                 BufferedReader in = new BufferedReader(
                         new InputStreamReader(socket.getInputStream()));
                 PrintWriter out = new PrintWriter(
                         new OutputStreamWriter(socket.getOutputStream()));
                 //读取客户端发来数据。
                 String line;
                 while((line = in.readLine()) != null) {//只要有数据就一直读
                     System.out.println("客户端发来的数据:"+line);
                     //可以给客户端作出响应-接收键盘输入的响应
                     System.out.println("回复的消息:");
                     String input = new Scanner(System.in).next();
                     //发出作为服务器的响应
                     out.println(input);
                     out.flush();//只要是输出,就需要刷新数据。
                 }
             } catch (Exception e) {
                 e.printStackTrace();
             }

         }
     }
}

5.2 客户端

  • 客户端连接相对简单,只需要循环,读和写即可。
public class Client {
    public static void main(String[] args) {
        //1.创建客户端,并指定ip和端口
        try {
            Socket socket = new Socket("127.0.0.1", 8200);
            System.out.println("连接成功");
            //2.循环发送信息
            while (true){
                PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                //3.输出
                System.out.println("发送给服务器信息:");
                String input = new Scanner(System.in).next();
                out.println(input);//向服务端发送指定数据
                out.flush();//把数据刷出去

                String line = in.readLine();//读取回声数据
                System.out.println("服务器相应:"+line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴琼老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值