zoukankan      html  css  js  c++  java
  • 基于JAVA套接字的简单网络聊天程序

    网络中进程之间如何通信

    本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类:

    • 消息传递(管道、FIFO、消息队列)
    • 同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)
    • 共享内存(匿名的和具名的)
    • 远程过程调用(Solaris门和Sun RPC)

    但这些都不是本文的主题!我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

    使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX  BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通信。就目前而言,几乎所有的应用程序都是采用socket,而现在又是网络时代,网络中进程通信是无处不在,这就是为什么说“一切皆socket”。

    TCP简介

      1.TCP介绍

        a>TCP协议:TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为:TCP)是一种面向连接的、可靠的、基于字节流的通信协议

        1.面向连接:先连接,再通信,好比打电话模型

        2.可靠的,相对于UDP,TCP传输更可靠,TCP通过一序列的机制(面向连接机制、发送应答机制)来保障传输的可靠性

        3.基于字节流的,UDP创建UDP socket——DGRAM:基于数据报通信方式,每一次发送的数据都是一个独立的整体,包含目标主机的ip地址、端口号及发送数据的内容

        b>TCP通信的三个步骤

        基于面向连接的:1.与服务端建立连接

                2.收发数据

      

              3.关闭连接

      2.TCP特点

        a>面向连接

        1.先建立连接,再进行通信

        2.TCP连接是一对一的,而UDP可以一对一或一对多,UDP适合做广播程序

        a>可靠传输:通过一序列机制来保障TCP传输数据比UDP更可靠

        1.传送应答机制

        2.超时重传机制

        3.错误校验

        4.流量控制/阻塞管理

    JavaSocket编程

            在Java环境下,Socket编程主要是指基于 TCP/IP协议 的网络编程。

            Socket工作过程包含以下四个步骤:

      (1) 创建Socket;

      (2) 打开连接到Socket的输入/输出流;

      (3) 按照一定的协议对Socket进行读/写操作;

      (4) 关闭Socket

     

    java中的Socket类主要包括两个:Socket(客户端)和 ServerSocket(服务器端)

    1)Socket 类

        Socket 类:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。 构造方法public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指 定的host是null ,则相当于指定地址为回送地址。
        成员方法 :

             public InputStream getInputStream() : 返回此套接字的输入流。如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。 关闭生成的InputStream也将关闭相关的Socket。

        public OutputStream getOutputStream() : 返回此套接字的输出流。 如果此Scoket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。 关闭生成的OutputStream也将关闭相关的Socket。
        public void close() :关闭此套接字。 一旦一个socket被关闭,它不可再使用。 关闭此socket也将关闭相关的InputStream和OutputStream 。
        public void shutdownOutput() : 禁用此套接字的输出流。 任何先前写出的数据将被发送,随后终止输出流。


      2)ServerSocket类
      ServerSocket 类:这个类实现了服务器套接字,该对象等待通过网络的请求。

      构造方法

         public ServerSocket(int port) :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上,参数port就是端口号。

        构造举例,代码如下: ServerSocket server = new ServerSocket(6666);

      成员方法

        public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法
    会一直阻塞直到建立连接。

    socket中TCP的三次握手建立连接详解

    我们知道tcp建立连接要进行“三次握手”,即交换三个分组。大致流程如下:

    • 客户端向服务器发送一个SYN J
    • 服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1
    • 客户端再想服务器发一个确认ACK K+1

    只有就完了三次握手,但是这个三次握手发生在socket的那几个函数中呢?请看下图:

    image

     

    从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

    客户端的connect在三次握手的第二个次返回,而服务器端的accept在三次握手的第三次返回。

    socket中TCP的四次握手释放连接详解

    上面介绍了socket中TCP的三次握手建立过程,及其涉及的socket函数。现在我们介绍socket中的四次握手释放连接的过程,请看下图:

    image

     

    图示过程如下:

    • 某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
    • 另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
    • 一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
    • 接收到这个FIN的源发送端TCP对它进行确认。

    这样每个方向上都有一个FIN和ACK。

    Java的Socket库函数与Linux的Socket系统调用之间的区别:

    Java通过JVM实现了优良的跨平台性,同一段写好的代码,移植到不同的操作系统上可直接执行,不受操作系统的限制,一处编译,到处执行,JAVA的SOCKET编程的底层原理是JVM将JAVA程序解析出来的参数传递给所对应的C++程序,由C++执行完之后回传给JAVA。

    而LINUX自带的SOCKET编程只能再LINUX操作系统下使用,同时JAVA与LINUX的API也不一致。

    一个小例子:

    服务端代码:

    package ray;
    import java.io.*;
    import java.net.*;
    public class Server {
        private static ServerSocket server;
    
        public static void main(String[] args) throws IOException{
            server = new ServerSocket(1100);
            System.out.println("服务器启动成功,等待用户接入...");
            //等待用户接入,直到有用户接入为止,Socket对象表示客户端
            Socket client = server.accept();
            //得到接入客户端的IP地址
            System.out.println("有客户端接入,客户IP:" + client.getInetAddress());
            InputStream in = client.getInputStream();//从客户端生成网络输入流,用于接收来自网络的数据
            
            OutputStream out = client.getOutputStream();//从客户端生成网络输出流,用来把数据发送到网络上
    
            byte[] bt = new byte[1024];//定义一个字节数组,用来存储网络数据
            int len = in.read(bt);//将网络数据写入字节数组
            String data = new String(bt, 0 , len);//将网络数据转换为字符串数据
            System.out.println("来自客户端的消息:" + data);
            out.write("我是服务器,欢迎光临".getBytes());//服务器端数据发送(以字节数组形式)
            client.close();//关闭套接字
        }
    }

    客户端代码:

    package ray;
    import java.io.*;
    import java.net.*;
    public class Client {
        private static Socket client;
    
        public static void main(String[] args) throws UnknownHostException, IOException {
            client = new Socket("127.0.0.1", 1100);
            System.out.println("连接服务器成功");
            InputStream in = client.getInputStream();//从客户端生成网络输入流,用于接收网络数据
            OutputStream out = client.getOutputStream();//从客户端生成网络输出流,用来发送数据
            out.write("我是客户端,欢迎光临".getBytes());//客户端数据发送
            byte[] bt = new byte[1024];//定义一个字节数组,用来存储网络数据
            int len = in.read(bt);//将网络数据写入字节数组
            String data = new String(bt, 0 ,len);//将网络数据转换为字符串数据
            System.out.println("来自服务器的消息:" + data);
            client.close();//关闭套接字
        }
    }

    运行结果展示:

    服务器端:

     

      

  • 相关阅读:
    7月自动化测试公开课通知
    招高级自动化测试工程师
    招聘软件开发工程师/开发实习生
    Selenium关键字驱动测试框架Demo(Java版)
    Eclipse+Selenium自动化测试脚本设计V1.0
    WebDriver基本API使用(基于Java)V1.0
    测试体系建设 免费咨询服务
    UFTQTP 12 新特性
    招聘自动化测试工程师
    AppScan学习笔记
  • 原文地址:https://www.cnblogs.com/zzydexiaowu/p/11988675.html
Copyright © 2011-2022 走看看