java实现hello/hi的简单的网络聊天程序与ServerSocket调用栈跟踪

java实现hello/hi的简单的网络聊天程序

  • 网络聊天采用TCP协议通过java实现

    import java.io.*;
    import java.net.Socket;
    
    public class Client {
        public static void main(String[] args) throws Exception{
    
            Socket socket = new Socket("192.168.31.68", 6666);
    
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String s = reader.readLine();
    
            OutputStream outputStream = socket.getOutputStream();
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
            writer.write(s);
            writer.newLine();
            writer.flush();
            socket.close();
        }
    }
    
    import java.io.InputStream;
    import java.net.InetAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class SeverDemo {
        public static void main(String[] args) throws Exception{
    
            ServerSocket serverSocket = new ServerSocket(6666);
            Object i = null;
    
            while(true) {
                Socket socket = serverSocket.accept(); 
    
                InputStream inputStream = socket.getInputStream();
    
                byte[] bytes = new byte[1024];
                int len = inputStream.read(bytes);
                String s = new String(bytes, 0, len);
                InetAddress address = socket.getInetAddress();
                System.out.println("from " + address.getHostAddress() + ": " + s);
    
                socket.close();
            }
        }
    
    
  • Server
  • Client

ServerSocket调用栈跟踪

  • 该图片描述的是socket0函数调用栈的关系
  • 从图中可以看出java从 serversocket -> 调用socketImpt -> abstractPlainSocketImpl -> DualStackSocketPlainImpl-> DualStackPlainImplt_socket0
  • 最后调用的是java中的native函数,可以在openjdk中看到(我使用的版本是openjdk 8.0)
// windows/native/java/net/DualStackPlainSocketImpl.c
/*
 * Class:     java_net_DualStackPlainSocketImpl
 * Method:    socket0
 * Signature: (ZZ)I
 */
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
  (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
    int fd, rv, opt=0;

//细看可以发现,这就是我们熟悉的linux下网络编程socket的api
    fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);

    if (fd == INVALID_SOCKET) {
        NET_ThrowNew(env, WSAGetLastError(), "create");
        return -1;
    }

    rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
    if (rv == SOCKET_ERROR) {
        NET_ThrowNew(env, WSAGetLastError(), "create");
    }

    SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);

    return fd;
}

  • 该图片是listen函数的调用栈关系
  • ServerSocket -> abstractPlaninSocketImpl -> DualStackSocketPlainImpl-> DualStackPlainImplt_listen0
  • native关键字声明的c源码如下
    /*
     * Class:     java_net_DualStackPlainSocketImpl
     * Method:    listen0
     * Signature: (II)V
     */
    JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_listen0
      (JNIEnv *env, jclass clazz, jint fd, jint backlog) {
        if (listen(fd, backlog) == SOCKET_ERROR) {
            NET_ThrowNew(env, WSAGetLastError(), "listen failed");
        }
    }
    

  • 该图片为bind函数的调用栈关系
  • ServerSocket -> abstractPlaninSocketImpl -> DualStackSocketPlainImpl-> DualStackPlainImplt_bind0
  • native关键字声明的c源码如下
/*
 * Class:     java_net_DualStackPlainSocketImpl
 * Method:    bind0
 * Signature: (ILjava/net/InetAddress;I)V
 */
JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
  (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
   jboolean exclBind)
{
    SOCKETADDRESS sa;
    int rv;
    int sa_len = sizeof(sa);

    if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
                                 &sa_len, JNI_TRUE) != 0) {
      return;
    }

    rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind);

    if (rv == SOCKET_ERROR)
        NET_ThrowNew(env, WSAGetLastError(), "JVM_Bind");
}

  • 该图片为accept函数的调用栈关系
  • ServerSocket -> abstractPlaninSocketImpl -> DualStackSocketPlainImpl-> DualStackPlainImplt_accept0
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
  (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
    int newfd, port=0;
    jobject isa;
    jobject ia;
    SOCKETADDRESS sa;
    int len = sizeof(sa);

    memset((char *)&sa, 0, len);
    newfd = accept(fd, (struct sockaddr *)&sa, &len);

    if (newfd == INVALID_SOCKET) {
        if (WSAGetLastError() == -2) {
            JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
                            "operation interrupted");
        } else {
            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                            "socket closed");
        }
        return -1;
    }

    ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
    isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
    (*env)->SetObjectArrayElement(env, isaa, 0, isa);

    return newfd;
}

Serversocket总结

  • java底层也是调用linux 网络api实现网络通信的
  • java中Serversocket创建时就对函数进行了socket和bind和listen操作,一个函数封装了linux下3个api
  • java中的accept对应与linux下accpet函数
  • Java中Socket客户端也是类似的情况,就不做重复分析。

原文地址:https://www.cnblogs.com/HMYaa/p/12001958.html

时间: 2024-10-11 21:25:44

java实现hello/hi的简单的网络聊天程序与ServerSocket调用栈跟踪的相关文章

利用java的Socket实现一个简单hello/hi聊天程序

利用java的Socket实现一个简单hello/hi聊天程序 首先,我们来用java实现一个简单的hello/hi聊天程序.在这个程序里,我学习到了怎么用socket套接套接字来进行编程.简单理解了一些关于socket套接字和底层调用的关系.关于java的封装思想,我学会了一些东西,java里真的是万物皆对象.还学到了一点多线程的知识. TCP 在这里,不得不先介绍以下TCP.TCP是传输层面向连接的协议.提供了端到端的进程之间的通信方式.TCP在通信之前要先建立连接.这里我们称这个建立连接的

基于Python完成一个hello/hi的简单的网络聊天程序

一.Socket 套接字简介 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开.读写和关闭等操作.套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信.网络套接字是IP地址与端口的组合. 传输层实现端到端的通信,因此,每一个传输层连接有两个端点.那么,传输层连接的端点是什么呢?不是主机,不是主机的IP地址,不是应用进程,也不是传输层的协议端口.传输层连接的端点叫做套接字(socket).根据RFC793的定义:端口号拼接到IP

以您熟悉的编程语言为例完成一个hello/hi的简单的网络聊天程序

在这片博文我们将使用python完成一个hello/hi的简单的网络聊天程序 先做一下准备工作 1.linux的socket基础api: 使用socket()创建套接字 int socket(int af, int type, int protocol); af为IP地址类型,AF_INE和AF_INET6分别对应ipv4和ipv6地址type是数据传输方式,Sock_stream(面向连接套接字)和sock_dgram(无连接套接字)protocol是传输协议,IPPROTO_TCP和IPPR

一个hello/hi的简单的网络聊天程序

我选择使用python来实现hello/hi的简单网络聊天程序,源代码包括两个部分,客户端代码和服务器端代码,源代码部分如下图所示: 服务器端代码 1 import socket 2 3 HOST = '127.0.0.1' 4 PORT = 8888 5 6 server = socket.socket() 7 server.bind((HOST, PORT)) 8 server.listen(1) 9 10 print(f'the server is listening at {HOST}:

一个hello/hi的简单的网络聊天程序和python Socket API与Linux Socket API之间的关系

1.Socket概述 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开.读写和关闭等操作.套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信.网络套接字是IP地址与端口的组合. 套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点.通信时,其中的一个网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给另一台主机的Socket中,使这段信息能传送到

ubuntu系统下使用python3实现简单的网络聊天程序

这是我的第二篇博客,很遗憾第一篇博客没有得到应有的认可. 可能是因为原理介绍和实操部分不够多,只是单纯分析了某一条指令在打开网页过程中,输出的变化. 在我的第二篇博客中把相关原理介绍的更加详细了,同时丰富了程序代码部分的介绍. 本文对通信相关知识点(如socket套接字.TCP/IP.HTTP通信协议).hello/hi网络聊天程序代码.python socke接口与Linux socket api之间的关系三个方面做了相关介绍 一.网络通信相关知识 首先必须明确一点,我们进行网络通信之前,必须

使用java实现一个hello/hi的简单的网络聊天程序

1.socket原理 Socket实质上提供了进程通信的端点.进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的.正如打电话之前,双方必须各自拥有一台电话机一样. 套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认. 1.服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态. 2.客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字.为此,客户端的套接字必须首先描述它要连接的服务器

hello/hi的简单的网络聊天程序

一.TCP/IP协议族 要想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,定义了主机如何连入因特网及数据如何在它们之间传输的标准,从字面意思来看TCP/IP是TCP和IP协议的合称,但实际上TCP/IP协议是指因特网整个TCP/IP协议族.不同于ISO模型的七个分层,TCP/IP协议参考模型把所有的TCP/IP系列协议归类到四个抽象层中. Internet

使用python实现一个hello/hi的简单的网络聊天程序

一.TCP/IP协议通信原理 TCP/IP协议包含的范围非常的广,它是一种四层协议,包含了各种硬件.软件需求的定义.TCP/IP协议确切的说法应该是TCP/UDP/IP协议.UDP协议(User Datagram Protocol 用户数据报协议),是一种保护消息边界的,不保障可靠数据的传输.TCP协议(Transmission Control Protocol 传输控制协议),是一种流传输的协议.他提供可靠的.有序的.双向的.面向连接的传输. 保护消息边界,就是指传输协议把数据当作一条独立的消