Based on the simple network chat program of java

A, TCP / IP protocol suite.

  To understand socket must first familiarize yourself with the TCP / IP protocol suite,  TCP / IP ( Transmission Control Protocol / Internet Protocol ) Transmission Control Protocol / Internet Protocol, defines how connected to the Internet and how to transfer data between host them standard, from the literal meaning TCP / IP is TCP and IP together, said the agreement, but in fact TCP / IP protocol refers to the entire Internet TCP / IP protocol suite. Unlike ISO seven layer model, TCP / IP protocol reference model all the TCP / IP family protocol classified into four abstraction layer.

          Internet communication protocol level division

  In the Internet layer, resolve IP addresses, looking to the destination IP next routing address of the destination. The network interface layer, is looking for a response to the hardware ( the MAC ) address. Data streams and a network topology as shown in FIG.

   And network topology data stream

  We know that a prerequisite if the two processes to communicate basic needs can only indicate a process in the local process communication, we can use the PID to uniquely identify a process, but PID only two processes only local, network PID a great chance of conflict, this time we need to open up that path, and we know the IP layer ip address uniquely identify the host, and TCP layer protocol and port number uniquely identify a host process, so we can use the ip address + protocol + port number that uniquely identifies a process network. 

Two, socket communication

  After the process of the network can be uniquely marked, they can use the socket to communicate, what is the socket it? We often socket translated into sockets, socket is an abstraction layer between the application layer and the transport layer, it is the TCP / IP layer of abstraction for the complex operations a few simple interface layer calls have been achieved with the supply process in the network communication. socket originated in UNIX , the Unix under the philosophy of thinking everything is a file, socket is an " open - read / write - close " mode of implementation, server and client are maintained a " file " , after establishing a connection open, you can to write their own content for other file read or read other contents, close the file at the end of the communication.

     Socket hierarchical relationship between communication and network protocols

  socket"打开/关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概是这样子的

       socket 客户端和服务端建立连接过程

*服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket
*服务器为socket绑定ip地址和端口号
*服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开
*客户端创建socket
*客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket
*服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端谅解请求
*客户端连接成功,向服务器发送连接状态信息
*服务器accept方法返回,连接成功
*客户端向socket写入信息
*服务器读取信息 *客户端关闭 *服务器端关闭

三、Java Socket API的使用

1)建立一个服务器ServerSocket,并同时定义好ServerSocket的监听端口;2)ServerSocket 调用accept()方法,使之处于阻塞。3)创建一个客户机Socket,并设置好服务器的IP和端口。4)客户机发出连接请求,建立连接。5)分别取得服务器和客户端ServerSocket 和Socket的InputStream和OutputStream.6) 利用Socket和ServerSocket进行数据通信。

四、基于java的socket编程代码

服务器端代码:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(1234);//服务器端口为1234

        System.out.println("服务器准备就绪~");

        // 等待客户端连接
        for (; ; ) {
            // 得到客户端
            Socket client = server.accept();
            // 客户端构建异步线程
            ClientHandler clientHandler = new ClientHandler(client);
            // 启动线程
            clientHandler.start();
        }
    }
    /**
     * 客户端消息处理
     */
    private static class ClientHandler extends Thread {
        private Socket socket;
        private boolean flag = true;

        ClientHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            super.run();
            System.out.println("新客户端连接:" + socket.getInetAddress() +
                    " P:" + socket.getPort());
            try {
                // 得到打印流,用于数据输出;服务器回送数据使用
                PrintStream socketOutput = new PrintStream(socket.getOutputStream());
                // 得到输入流,用于接收数据
                BufferedReader socketInput = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                InputStream in = System.in;
                BufferedReader input = new BufferedReader(new InputStreamReader(in));


                do {
                    // 从客户端拿到一条数据
                    String str = socketInput.readLine();
                    if ("bye".equalsIgnoreCase(str)) {
                        flag = false;
                        // 回送
                        socketOutput.println("bye");
                    } else {
                        // 打印到屏幕。并回送数据长度
                        System.out.println("client:"+str);
                        String s = input.readLine();
                        socketOutput.println(s);
                    }
                } while (flag);

                socketInput.close();
                socketOutput.close();

            } catch (Exception e) {
                System.out.println("连接异常断开");
            } finally {
                // 连接关闭
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("客户端已退出:" + socket.getInetAddress() +
                    " P:" + socket.getPort());
        }
    }
}

客户端代码:

import java.io.*;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket();
        // 连接本地,端口2500;
        socket.connect(new InetSocketAddress(Inet4Address.getLocalHost(), 2500));

        //打印客户端以及服务器相关信息
        System.out.println("已发起服务器连接,并进入后续流程~");
        System.out.println("客户端信息:" + socket.getLocalAddress() + " P:" + socket.getLocalPort());
        System.out.println("服务器信息:" + socket.getInetAddress() + " P:" + socket.getPort());

        try {
            // 发送接收数据
            send(socket);
        } catch (Exception e) {
            System.out.println("异常关闭");
        }

        // 释放资源
        socket.close();
        System.out.println("客户端已退出~");

    }

    private static void send(Socket client) throws IOException {
        // 构建键盘输入流
        InputStream in = System.in;
        BufferedReader input = new BufferedReader(new InputStreamReader(in));


        // 得到Socket输出流,并转换为打印流
        OutputStream outputStream = client.getOutputStream();
        PrintStream socketPrintStream = new PrintStream(outputStream);


        // 得到Socket输入流,并转换为BufferedReader
        InputStream inputStream = client.getInputStream();
        BufferedReader socketBufferedReader = new BufferedReader(new InputStreamReader(inputStream));

        boolean flag = true;
        do {
            // 键盘读取一行
            String str = input.readLine();
            socketPrintStream.println(str);
            // 从服务器读取响应信息,如果是bye,退出循环
            String echo = socketBufferedReader.readLine();
            if ("bye".equalsIgnoreCase(echo)) {
                flag = false;
            }else {
                System.out.println("server:"+echo);
            }
        }while (flag);

        // 资源释放
        socketPrintStream.close();
        socketBufferedReader.close();

    }
}

五、实验结果

    

六、Java Socket API和Linux Socket API关系探究

1、 java与linux api调用关系

我们知道java的socket实现是通过调用操作系统的socket api实现的,下面图表展示其调用关系

 

从java代码到linux内核是如何一步步调用的?

2、new ServerSocket(1234)
ServerSocket serverSocket = new ServerSocket(1234);
从java角度看,上一行代码就是创建一个端口号为:1234的ServerSocket.
但从底层实现来讲,它包含了如下三个重要操作

*socket创建
*socket绑定
*socket的侦听

 socket创建

  若要执行网络I/O,进程首先就要调用一个socket函数,并会指定一个期望的协议类型和套接口类型,socket函数成功的时候会返回一个小的非负整数, 因在Linux中一切皆文件,所以这个整数表示一个文件描述符,此时会创建socket对应的结构,并将其和一个已经打开的文件对应。

socket绑定

  对于TCP协议,bind函数可以和一个IP和一个端口绑定;此时该套接口处于TCP_CLOSE状态,如果不绑定端口号,则内核会为该套接口绑定一个临时的端口,如果不绑定IP地址,对于服务端而言,内核就会将客户端发送的SYN的目的IP地址作为服务器的源IP地址。

socket的侦听

  由上面可以知道,listen会将主动转为被动连接,会将套接口由closed状态转换为linsten状态,并且维护了两个队列。

此时会和客户端进行三次握手来建立连接

 3、Socket socket = server.accept()

  linux中由TCP服务器调用,从已完成的连接队列的队头返回下一个已完成连接;成功则会返回由内核创建的新的描述符;在并发服务器中,accept()返回后,服务器会调用fork函数,创建一个子进程,由该子进程来和客户端进行通讯,此时套接口对应文件描述符的引用计数会增加,同时父进程会关闭该已连接套接字,即会将引用计数减少。然后在原有的监听套接口上,继续监听有无其他连接,当由连接的时候,再次accept处理连接。

 

参考链接:https://blog.csdn.net/vipshop_fin_dev/article/details/102966081 

Guess you like

Origin www.cnblogs.com/double-wjl/p/12020008.html