计算机网络之socket,什么是socket

两个进程之间如果需要通信,最基本的前提,是能够唯一地标识一个进程,在本地进程通信中,我们可以使用PID,来唯一标识一个进程,

但PID只在本地唯一网络中的两个进程PID冲突的几率还是有的。

 

 

IP层的IP地址,可以唯一标识一台主机,而TCP协议和端口号可以唯一标识主机的一个进程。

 

这样我们可以利用IP地址加协议加端口号来唯一标识网络中的一个进程,就可以使用Socket进行通信了。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

什么是Socket

Socket是对TCP/IP协议的抽象,是操作系统对外开放的接口。

 

Socket适应其他的网络协议,使得程序员更方便地使用TCP/IP协议栈。

 

对TCP/IP协议的抽象,从而形成了我们知道的最基本的函数接口。

比如create,listen,connect,accept,send,read,write,等等。

 

Socket起源于UNIX,

 

Socket基于从打开到读和写,再到关闭的这种模式去实现的。

 

服务器和服务端各自维护一个文件,在建立连接打开后,可以向自己的文件写入内容,供对方读取,或者读取对方的内容,在通讯结束时,

就会关闭文件。

 

Socket通信流程(使用TCP协议通信的Socket为例讲解)

 

 

 

 

服务器首先创建通信ServerSocket,为ServerSocket绑定IP地址和端口号。

 

紧接着服务器创建Socket监听端口号的请求,随时准备接受客户端发来的连接。

 

服务器的Socket只是listen,没有打开 。

 

此时假设客户端创建了Socket,打开了Socket,并根据服务器的IP地址和端口号尝试去连接服务器的Socket,服务器的Socket接收到客户端Socket

请求,被动地打开,开始接收客户端的请求,直到客户端返回连接信息,这时候服务器的Socket进入到阻塞状态,即accept方法需要等待客户端返回连接信息后,才返回。同时开始接收下一个客户端的连接请求。

 

客户端在连接成功之后呢,向服务器发送连接状态信息,服务端在接收到客户端的连接信息之后,将accpet方法返回,并提示连接成功。

 

客户端向Socket去写入信息,服务器能收到并读取相关的信息,最 后在发送完数据后,客户端会关闭socket,服务端也会关闭Socket

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Socket相关的面试题

 

 

 

 

TCPServer

package com.interview.javabasic.socket;

 

import java.net.ServerSocket;

import java.net.Socket;

 

public class TCPServer {

    public static void main(String[] args) throws Exception{

        //创建通信ServerSocket,并将ServerSocket绑定到6500端口

        ServerSocket ss = new ServerSocket(65000);

        //死循环,使得socket一直等待并处理客户端发送过来的请求;

        while (true){

            //监听6500端口,直到客户端返回连接信息后才返回

            Socket socket = ss.accept();

            //获取客户端的请求信息后,执行相关业务逻辑

        new LengthCalculator(socket).start();

        }

 

 

    }

}

 

TCPClient

package com.interview.javabasic.socket;

 

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

 

public class TCPClient {

    public static void main(String[] args) throws Exception{

        //创建socket,并指定连接的是本机的端口号为65000的服务器的socket

        Socket socket = new Socket("127.0.0.1",65000);

        //获取输出流

        OutputStream os = socket.getOutputStream();

        //获取输入流

        InputStream is = socket.getInputStream();

        //将要传递给Server的字符串参数转换成byte数组,并把数组写入到输出流中

        os.write(new String("hello world").getBytes());

        int ch = 0;

        byte[] buff = new byte[1024];

        //buff主要用来读取输入的内容,存成byte数组,ch主要用来获取读取数组的长度

        ch = is.read(buff);

        //将接收流的byte数组转换成字符串,这里是从服务端回发回来的字符串参数的长度

        String content = new String(buff,0,ch);

        System.out.println(content);

        //不要忘记关闭输入输出流及socket

        is.close();

        os.close();

        socket.close();

    }

}

 

 

LengthCalculator

 

package com.interview.javabasic.socket;

 

import jdk.internal.util.xml.impl.Input;

 

import javax.imageio.IIOException;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

 

public class LengthCalculator extends Thread{

    //以socket为成员变量

    private Socket socket;

 

    //构造函数,接收服务器端socket实例,并且将该实例传递给本身的成员变量

    public LengthCalculator(Socket socket){

        this.socket = socket;

    }

 

    @Override

    public void run(){

        try{

            //获取socket的输出流,

            OutputStream os = socket.getOutputStream();

            //获取socket的输入流

            InputStream is = socket.getInputStream();

            int ch = 0;

            byte[] buff = new byte[1024];

            //buff主要用来读取输入的内容,存成byte数组(read函数参数为数组),ch主要用来获取读取数组的长度

            ch = is.read(buff);

            //将接收流的byte数组转换成字符串,这里获取的内容是客户端发送过来的字符串参数

            String content = new String(buff,0,ch);

            System.out.println(content);

            //往输出流里写入获得的字符串长度,回发给客户端

            //write函数参数又是数组了,所以得从字符串转换成数组

            os.write(String.valueOf(content.length()).getBytes());

            //不要忘记关闭输入输出流以及socket

            is.close();

            os.close();

            socket.close();

        }catch (IOException e){

            e.printStackTrace();

        }

    }

 

 

}

 

UDPServer

 

package com.interview.javabasic.socket;

 

import java.net.DatagramPacket;

import java.net.DatagramSocket;

 

public class UDPServer {

    public static void main(String[] args) throws  Exception{

        //服务端接收客户端发送的数据报

        DatagramSocket socket = new DatagramSocket(65001);//监听的窗口号

        byte[] buff  = new byte[100];//存储从客户端接收到的内容

        DatagramPacket packet = new DatagramPacket(buff,buff.length);

        //packet接收客户端发过来的内容,并将内容封装进DatagramPacket对象中

        socket.receive(packet);

 

 

        byte[] data = packet.getData(); //从DatagramPacket对象 中获取到真正存储的数据

        //将数据从二进制转换成字符串形式

        String content = new String(data,0,packet.getLength());

        System.out.println(content) ;

        //将要发送给客户端的数据转换成二进制

        byte[] sendedContent = String.valueOf(content.length()).getBytes();

        //服务端给客户端发送数据报

        //从DatagramPacket对象中获取到数据的来源地址与端口号

        DatagramPacket packetToClient = new DatagramPacket (sendedContent,

                sendedContent.length,packet.getAddress(), packet.getPort());

        socket.send(packetToClient); //发送数据给客户端

       

    }

}

 

UDPClient

 

package com.interview.javabasic.socket;

 

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

 

public class UDPClient {

    public static void main(String[] args) throws Exception{

        //客户端发数据报给服务端

        DatagramSocket socket  =  new DatagramSocket();

        //要发送给服务端的数据

        byte[] buf  = "Hello World".getBytes();

        //将IP地址封装成InetAddress对象

        InetAddress address  = InetAddress.getByName("127.0.0.1");

        //将要发送给服务端的数据封装成DatagramPacket对象 需要填写上ip地址与端口号

        DatagramPacket packet = new DatagramPacket(buf,buf.length,address,

                65001);

        //发送数据给服务端

        socket.send(packet);

 

        //客户端接收服务端发送过来的数据报

        byte[] data = new byte[100];

        //创建DatagramPacket对象用来存储服务端发送过来的数据

        DatagramPacket receivePacket = new DatagramPacket(data,data.length);

        //将接收到的数据存储到DatagramPacket对象中

        socket.receive(receivePacket);

        //将服务端发送过来的数据取出来并打印到控制台

        String content = new String(receivePacket.getData(),0,

                receivePacket.getLength());

        System.out.println(content);

    }

}

 

 

欢迎大家关注我的微信公众号,获取你不知道的宝藏。

 

posted @ 2020-03-30 16:39  代码改变我的世界  阅读(1149)  评论(0编辑  收藏  举报