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 的通信协议层次划分

  在Internet层,解析IP地址,寻找通往目标IP的目的地的下一个路由地址。在网络接口层,则是寻找响应的硬件(MAC)地址。数据流以及网络拓扑结构如下图所示。

   数据流以及网络拓扑结构

  我们知道两个进程如果需要进行通讯最基本的一个前提能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。

二、socket通信

  能够唯一标示网络中的进程后,它们就可以利用socket进行通信了,什么是socket呢?我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

    Socket通信与网络协议之间的层次关系

  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

原文地址:https://www.cnblogs.com/double-wjl/p/12020008.html

时间: 2024-10-20 07:51:18

hello/hi的简单的网络聊天程序的相关文章

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

基于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之间的关系三个方面做了相关介绍 一.网络通信相关知识 首先必须明确一点,我们进行网络通信之前,必须

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

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

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

使用Tcp协议的Socket编程主要用到两个类,Socket和ServerSocket.ServerSocket本身也是一个Socket,只是它同时包含了一些额外的服务器终端的功能,比如监听端口,等待客户端Socket前来建立连接等.通过accept方法一旦和客户端建立起连接,就会返回一个普通的Socket和客户端Socket进行对等的通信. 本文的Demo实现的功能很简单,用户输入消息,发送给服务器,服务器原封不动返回给客户端.原理是:启动一个服务器线程和两个客户端线程.服务器线程监听2000

实现一个的简单的网络聊天程序

本次实验采用Java语言,编写了一个简单的聊天室程序,可以实现多人之间的聊天.以下将对该程序进行详尽分析,并对比分析该编程语言提供的网络接口API与Linux Socket API之间的关系. 1. 网络通信相关要素 1) 协议 通信的协议还是比较复杂的, java.net 包中包含的类和接口,它们提供低层次的通信细节.我们可以直接使用这 些类和接口,来专注于网络程序开发,而不用考虑通信的细节. java.net 包中提供了两种常见的网络协议的支持: TCP:传输控制协议 (Transmissi

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

使用Java的Socket实现客户端和服务器端之间的连接,实现客户端重复发送数据到服务器端的功能.即,用户可以在控制台不断输入内容,并将内容逐一发送给服务端.并在服务端显示. socket定义 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.建立网络通信连接至少要一对端口号(socket).socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装