java tcp底层源码分析

TCP服务端实现

 

     //定义服务器端socket并指定监听端口

    ServerSocket serverSocket = new ServerSocket(5937);

    //调用阻塞式方法来获取客户端连接的socket

    Socket socket = serverSocket.accept();

     //获取客户端socket的输入流

    InputStream inputStream =socket.getInputStream();

    //读取客户端socket的输入流的内容并输出

    byte[]buffer = new byte[512];

    inttemp;

    while((temp = inputStream.read(buffer)) != -1) {

         System.out.println(new String(buffer, 0, temp));

    }

 

TCP客户端实现

 

     //产生socket对象,制定服务器地址和服务器监听的端口号

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

    //获取socket的输出流

    OutputStream outputStream =socket.getOutputStream();

    //将数据放入输出流中

    outputStream.write(msg.getBytes());

 

 

 

 

 

//定义服务器端socket并指定监听端口

ServerSocket serverSocket = new ServerSocket(5937);

//

 

java.net.ServerSocket.java96

 

/**

     * Constructs a new {@code ServerSocket}instance bound to the given {@code localAddress}

     * and {@code port}. The backlog is set to{@code backlog}.

     * If {@code localAddress == null}, the ANYaddress is used.

     * If {@code port == 0}, a port will beassigned by the OS.

     *

     * @throws IOException if an error occurs while creating the socket.

     */

public ServerSocket(int port, intbacklog, InetAddress localAddress) throwsIOException {

        checkListen(port);

        this.impl = factory != null ? factory.createSocketImpl()

                : new PlainServerSocketImpl();

        InetAddress addr = (localAddress == null) ? Inet4Address.ANY: localAddress;

 

        synchronized (this) {

            impl.create(true);

            try {

                impl.bind(addr,port);

                readBackBindState();

                impl.listen(backlog> 0 ? backlog : DEFAULT_BACKLOG);

            } catch (IOException e) {

                close();

                throw e;

            }

        }

    }

 

 

//

java:

FileDescriptor fd;

c++:

int fd;

 

int fd =jniGetFDFromFileDescriptor(env, javaFd);

定义:JNIHelp.cpp 320

 

FileDescriptor javaFd =jniCreateFileDescriptor(env, fd);

定义:JNIHelp.cpp 309

//

 

 

 

1.impl.create(true):

//

 

libcore.io.IoBridge.java606

 

public static FileDescriptor socket(boolean stream)

 

FileDescriptor fd;

fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);

 

(stream : true)

 

获得远端fd

 

 

libcore_io_posix.cpp 1419

 

static jobject Posix_socket(JNIEnv* env,jobject, jint domain, jint type, jint protocol)

 

socket(domain, type,protocol)

 

//

 

libcore.io.IoBridge.java376

 

 

private static voidsetSocketOptionErrno(FileDescriptor fd, int option, Object value)

 

Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR, booleanToInt((Boolean) value));

 

(value : Boolean.TRUE)

(booleanToInt((Boolean)value) : 1)

 

 

libcore_io_posix.cpp 1297

 

static void Posix_setsockoptInt(JNIEnv* env, jobject, jobject javaFd, jintlevel, jint option, jint value)

 

setsockopt(fd, level,option, &value, sizeof(value)))

 

 

//

 

2.impl.bind(addr, port):

 

libcore.io.IoBridge.java79

 

public static void bind(FileDescriptor fd,InetAddress address, int port)

 

Libcore.os.bind(fd, address, port);

 

 

libcore_io_posix.cpp 486

 

static void Posix_bind(JNIEnv* env, jobject, jobject javaFd, jobjectjavaAddress, jint port)

 

NET_FAIURE_RETRY(env, int, bind, javaFd, sa, sa_len);

宏定义:

bind(javaFd, sa, sa_len);

 

sa:

sockaddr_storage ss;

socklen_t sa_len;

inetAddressToSockaddr(env,javaAddress, port, ss, sa_len);

const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);

 

//

3.readBackBindState():

 

InetAddress localAddress

localAddress = IoBridge.getSocketLocalAddress(impl.fd);

获得本地IP端口

 

libcore.io.IoBridge.java627

 

public static InetAddress getSocketLocalAddress(FileDescriptor fd)

 

SocketAddress sa =Libcore.os.getsockname(fd);

 

 

libcore_io_posix.cpp 409

 

static jobject doGetSockName(JNIEnv* env,jobject javaFd, bool is_sockname)

 

 

sockaddr_storage ss;

sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);

socklen_t byteCount = sizeof(ss);

 

getsockname(fd, sa,&byteCount)

 

 

//

 

4.impl.listen(backlog > 0 ? backlog : DEFAULT_BACKLOG):

 

java.net.PlainSocketImpl.java271

 

protected void listen(int backlog)

 

Libcore.os.listen(fd,backlog);

 

 

libcore_io_posix.cpp 965

 

static void Posix_listen(JNIEnv* env, jobject, jobject javaFd, jint backlog)

 

listen(fd, backlog);

 

backlog = DEFAULT_BACKLOG 50

 

 

//

 

//调用阻塞式方法来获取客户端连接的socket

Socket socket = serverSocket.accept();

 

//

 

/**

     * Waits for an incoming request and blocksuntil the connection is opened.

     * This method returns a socket objectrepresenting the just opened

     * connection.

     *

     * @return the connection representing socket.

     * @throws IOException

     *             if an error occurs while acceptinga new connection.

     */

    public Socket accept() throwsIOException {

        checkOpen();

        if(!isBound()) {

            throw new SocketException("Socket is not bound");

        }

 

        Socket aSocket = new Socket();

        try {

            implAccept(aSocket);

        } catch (IOException e) {

            aSocket.close();

            throw e;

        }

        return aSocket;

    }

 

 

 

1.isBound():

 

构造函数中readBackBindState() -> isBound = true;

 

2.implAccept(aSocket):

 

2.1.impl.accept(aSocket.impl):

 

(java.net.PlainSocketImpl.java80)

 

protected void accept(SocketImpl newImpl)

 

FileDescriptor clientFd =Libcore.os.accept(fd, peerAddress);

newImpl.fd.setInt$(clientFd.getInt$());

newImpl.address = peerAddress.getAddress();

newImpl.port = peerAddress.getPort();

获得对方远端IP端口

 

 

(libcore_io_posix.cpp460)

 

static jobject Posix_accept(JNIEnv* env,jobject, jobject javaFd, jobject javaInetSocketAddress)

 

jint clientFd =NET_FAIURE_RETRY(env, int, accept, javaFd, peer,peerLength);

 

宏定义:

 

accept(javaFd, peer,peerLength)

 

peer:

sockaddr_storage ss;

socklen_t sl = sizeof(ss);

memset(&ss, 0, sizeof(ss));

sockaddr* peer =(javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;

socklen_t* peerLength =(javaInetSocketAddress != NULL) ? &sl : 0;

 

//

 

2.2.aSocket.accepted():

 

InetAddress localAddress

localAddress = IoBridge.getSocketLocalAddress(impl.fd);

(获得对方本地IP端口)

 

同上1.3

 

//

 

//获取客户端socket的输入流

InputStream inputStream = socket.getInputStream();

//读取客户端socket的输入流的内容并输出

byte[] buffer= new byte[512];

int temp;

while ((temp = inputStream.read(buffer))!= -1) {

     System.out.println(new String(buffer, 0, temp));

}

 

//

 

@Override protected synchronized InputStream getInputStream() throws IOException {

        checkNotClosed();

        return new PlainSocketInputStream(this);

    }

 

    private static class PlainSocketInputStream extends InputStream {

        private final PlainSocketImpl socketImpl;

 

        public PlainSocketInputStream(PlainSocketImpl socketImpl) {

            this.socketImpl = socketImpl;

        }

 

        @Override public int available() throws IOException {

            return socketImpl.available();

        }

 

        @Override public void close() throws IOException {

            socketImpl.close();

        }

 

        @Override public int read() throws IOException {

            return Streams.readSingleByte(this);

        }

 

        @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {

            return socketImpl.read(buffer, byteOffset,byteCount);

        }

    }

 

 

 

 

 

/**

     * For PlainSocketInputStream.

     */

    private int read(byte[] buffer, int offset, int byteCount) throwsIOException {

        if(byteCount == 0) {

            return 0;

        }

        Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);

        if(shutdownInput) {

            return -1;

        }

        int readCount = IoBridge.recvfrom(true, fd, buffer, offset, byteCount, 0, null, false);

        // Return of zero bytes for a blocking socket means atimeout occurred

        if(readCount == 0) {

            throw new SocketTimeoutException();

        }

        // Return of -1 indicates the peer was closed

        if(readCount == -1) {

            shutdownInput = true;

        }

        return readCount;

    }

 

 

 

(libcore.io.IoBridge.java549)

 

public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected)

 

result = Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags,srcAddress);

 

 

(libcore_io_posix.cpp1185)

 

static jint Posix_recvfromBytes(JNIEnv*env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jintbyteCount, jint flags, jobject javaInetSocketAddress)

 

NET_FAIURE_RETRY(env,ssize_t, recvfrom, javaFd, bytes.get() + byteOffset, byteCount, flags, from, fromLength);

 

宏定义:

 

recvfrom(javaFd,bytes.get() + byteOffset, byteCount, flags, from, fromLength);

 

 

bytes : ScopedBytesRWbytes(env, javaBytes);

byteOffset : 0

flags : 0

from : BULL

fromLength : 0

 

 

问题:

为什么java tcp接收底层代码是recvfrom()而不是read()?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值