java实现TCP socket和UDP socket的实例

目录
  • 概述
  • 传输层概述
  • TCP套接字编程
    • 大致过程
    • 详细过程
  • UDP套接字编程
  • 补充

概述

我们在网络编程时,通常是让我们本地的应用程序和远程的应用程序进行通信,也就是分布式的进程之间的通信,比如我写的程序A和小明的程序B进行通信,我的程序运行时在本机就是一个进程,是有pid号的,小明的也是。那这两个程序是怎么通信的呢?

这就要理解网络分层的概念了,网络层实现的是主机到主机之间的通信,网络层的实现是ip协议,通过各自的ip地址就能实现远程数据传输,而网络层只是保证了主机A的数据能够到达主机B,并不能够识别和发送到对应的进程,而传输层实现的是进程到进程的通信,对网络层的功能进行了加强,能够把数据交付给对应的进程。

有了传输层的功能,我们用户才能进一步的去实现自己的应用层协议,实现应用。当我们需要远程通信时只需要通过下层的传输层传输数据即可

但是想象一下,每次我在应用层发送数据时至少都是需要把 要发送的信息、本机ip、本地端口、目的ip和目的端口这五个数据通过层间接口交给传输层(对于TCP协议来说的,UDP无连接不需要应答所以不需要本机ip和端口),如下图

但是每一次应用层向传输层发送数据时都需要发送这些数据是不是很多余?TCP一旦双方建立起连接了,那么除了数据部分,其他的都是相同的,没有必要每次发送数据都发送一遍,为了减少层间接口的传输量,就出现了socket,操作系统底层维护一个列表,用于存放多个socket,即多个会话关系。

        socket套接字是传输层提供给应用层的一个API,底层实现就是一个整数,是传输层和应用层的一个约定,该整数就像是打开一个文件并得到文件句柄一样,对这个句柄进行的操作就是对该文件进行操作,方便管理。

有了socket之后应用层数据的传输就变为了这样

传输层概述

先来说说网络层的ip,ip协议在网络上发送数据包是不可靠的,有可能造成丢失,乱序等问题,如发送数据包到对应的路由器,路由器有接收缓冲区,如果发现同一时刻来的数据包太多了,缓冲区放不下,它是可以把装不下的数据包扔掉的。这就是不可靠的传输。

传输层提供了TCP和UDP两种服务:

  • TCP:对ip协议进行了增强,通过一些方式来达到可靠的数据传输
  • UDP:不可靠的数据传输,它只对ip增加了进程到进程之间的通信,其他的就没了,原原本本

TCP套接字编程

TCP socket反应的是应用进程A和应用进程B会话关系的一个代表,A对对应的socket发送数据,就是A对B发送数据;A对对应的socket接收数据就是对B接收数据。

大致过程

1.服务器进程必须运行,创建一个欢迎socket,该socket和本地的端口进行捆绑,在欢迎socket上阻塞式的等待接收客户端的连接

2.客户端创建本地的套接字,隐式捆绑到本地的端口,再指定服务器的ip和端口进行连接。

3.服务器接受来自用户端的请求 ,解除阻塞式等待,返回一个 新的socket(与欢迎socket不 一样),与客户端通信

4.连接API调用有效时,客户端与服务器建立了TCP连接,即可以通信了

代码如下:

@Test
public void server() throws IOException {
    //1.建立欢迎socket,绑定一个监听的端口号
    ServerSocket welcomeSocket = new ServerSocket(8080);
    //2.阻塞的等待客户端的连接请求,连接请求到来时创建一个新的socket,与客户端绑定
    Socket socket = welcomeSocket.accept();
    //6.从该socket接收数据
    InputStream is = socket.getInputStream();
    int len = 0;
    while ((len = is.read()) != -1) {
        System.out.print((char) len);
    }
    socket.close();
}

@Test
public void client() throws IOException {
    //3.建立一个客户端这边的socket
    Socket socket = new Socket();
    //4.阻塞的请求连接到指定ip和端口号的服务器进程
    socket.connect(new InetSocketAddress("localhost", 8080));
    //5.发送数据到该socket
    OutputStream os = socket.getOutputStream();
    byte[] bytes = new byte[1024];
    os.write("hello".getBytes());
    socket.shutdownOutput();
}

详细过程

首先来看java中socket的结构体(类),其他语言都大同小异。

public abstract class SocketImpl implements SocketOptions {
    /**
     * The IP address of the remote end of this socket.远程主机的ip地址
     */
    protected InetAddress address;
    /**
     * The port number on the remote host to which this socket is connected.远程主机的端口
     */
    protected int port;
    /**
     * The local port number to which this socket is connected.本地端口
     */
    protected int localport;
    /**
     *实际还有一个本机的ip地址,被省略掉了
     */
}

InetAddress类就不介绍了,里面就是封装了ip地址等信息。

ServerSocket和Socket类是一个东西,只时名字不同而已。具体可以看源码。

可以得出来socket其实大致就是这么一个6元组(这里省略了socket的状态),当我们应用进程创建socket时,操作系统给该socket一个唯一的整数标识,且肯定是要保存是哪个进程创建的socket,所以pid也应该对应起来,方便日后能给找到对应的进程。

我们举例如下图的一个通信过程来具体的说明socket的通信过程:

1.首先服务器进程先建立一个欢迎socket,用于监听连接请求,并且绑定端口号为8080,阻塞监听客户端的连接请求,如下图

2.这时候客户端也新建一个socket(该socket以后会当做和服务器的通信socket),这个socket不用像服务器那样绑定一个固定的端口号用于监听,但是操作系统会给该socket绑定一个随机的端口,这里假设是4567。如下图,此时客户端的1号socket还是一个无效的状态,因为还没有连接

3.客户端用刚刚建立的socket和远程服务器进行连接connect,指明服务器的地址和对应的端口号,此时socket的状态也就补齐了,随后客户端进入阻塞模式进行TCP的三次握手,请求和服务器建立连接

4.服务器和客户端TCP连接建立好后,解除阻塞,并且返回一个新的socket(因为不能占用welcome socket),新的socket就是服务器和客户端的一个连接状态,该socket变为一个有效状态,此时服务器继续进入阻塞状态等待此socket的数据。

5. 连接建立好后,客户端也解除阻塞,它的socket1也变为有效状态。然后客户端把需要发送的数据和对应的socket1(输出流里面封装了socket)交给下层传输层,此时的传输层得到了它相应的信息,根据socket就可以从表中查到需要发送的目的ip和端口,继续交给下层直到发送到服务器。

6.服务器的tcp层收到数据包后,查看源ip、目的ip、源端口、目的端口,一一对照自己的socket表,发现2号socket真好对应,且得知2号socket是pid为100的应用进程,所以tcp把数据发送给该进程,服务器的java进程解除阻塞,read客户端发送来的数据。

7.最后如果服务器和客户端某一方没有数据发了,不想建立连接了,就调用close方法,进行TCP的四次挥手,解除连接,使两边对应的socket都变得无效。

UDP套接字编程

UDP是没有建立连接这一过程的,也不需要维持会话关系,每个报文都是独立传输的。因此UDP只能使用一个整数来标志当前应用进程,不能够固定住对方的ip和端口号,因为UDP通信前不建立连接,可能现在发的这个ip和端口是一台主机,而下次用同样的ip和端口发的就是另一台主机了。所以每次发送的时候都需要指定发送的目的ip和端口。

UDP的socket大致如下

java中UDPsocket结构如下

public abstract class DatagramSocketImpl implements SocketOptions {

    /**
     * The local port number.
     */
    protected int localPort;
    /**
     * 省略本机ip
     */
}

UDP简单套接字编程如下:

@Test
public void server() throws IOException {
    //1.创建udp socket,并绑定到本机ip和8080端口号
    DatagramSocket socket = new DatagramSocket(8080);
    byte[] buff = new byte[100];
    //存放数据包的容器
    DatagramPacket packet = new DatagramPacket(buff, 0, buff.length);
    //接收数据包
    socket.receive(packet);
    System.out.println(new String(packet.getData(), 0, packet.getLength()));
    socket.close();
}

@Test
public void client() throws IOException {
    DatagramSocket socket = new DatagramSocket();
    byte[] data = "hello".getBytes();
    //指明发送端的ip和端口和数据部分
    DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("127.1.1.1"), 8080);
    //使用该socket发送数据包
    socket.send(packet);
}

详细步骤如下:

1.服务器创建一个udp的socket,绑定端口8080用于监听数据包,通过调用receive方法阻塞的监听。

2.客户端创建一个自己的socket,该socket的端口假设操作系统分配的是4567

3.客户端发送数据包、目标ip和目标端口给下层的传输层,传输层就能够得到源ip、源端口、目的ip和目的端口,然后一步一步的打包交给下层,发送到服务器主机,服务器主机通过数据包的目的ip和目的端口,对比发现socket对应,然后把数据发送给对应的pid号为100的应用进程。

4.服务器解除阻塞,收取数据。

5.最后关闭连接,删除对应的socket

注意的是UDP是没有welcome socket的

补充

再补充一个小知识点,那就是端口号和进程的联系

进程pid是否可供计算机之间使用呢?

应用层代表的就是我们的应用进程,既然进程代表着应用层,那为什么进程pid不能作为应用层的标识来进行计算机之间传输呢?而是使用额外的端口号呢?

(1)首先: 单个计算机中的进程使用pid来标志的,但是在互联网环境下使用的计算机操作系统种类很多,而不同的操作系统又使用不同格式的进程标识符,为了使运行不同操作系统的计算机的应用进程能够互相通信,就必须使用统一的方法对TCP/IP体系的进程进行标识;

(2)其次:一个机器上运行的进程不能成为互联网上通信的最后终点,因为进程的创建和撤销都是动态的,通信的一方几乎无法识别对方机器的进程是哪一个;

例如:要和互联网上某个邮件服务器联系,几乎无法得知其服务器邮件进程的进程标识符,因为进程标识符是随机分配的;所以,我们并不一定要知道这个服务器服务是由目的主机那个进程实现的;

所以,不能使用进程标识符来做计算机之间的进程通信标识;

如何使用端口号进行通信?
   
    两个计算机中进程要互相通信,除了必须指定对方的IP地址,还需要知道对方的端口号;

例如:我们寄信的过程说明,当我们要给某人写信时,除了通讯地址还要有收件人的名字,这里的通讯地址就是IP地址,但是收件人的名字却不是进程标识符,因为有可能这个人用的是法文、德文、英文名字,快递员无法识别,因此采用 “菜鸟驿站" 的模式,为每个地址配备多个快递箱(端口号),快递员只是将包裹放置具体的快递箱(端口号),收件人通过监听某个快递箱是否有快递(TCP或者UDP),来进行数据接收,最终拿到需要的包裹(数据);

端口号如何分配?

(1)服务器使用的端口号:

一类为熟知端口号或系统端口号(0~1023),将一些重要的应用程序进行登记,所以将一些端口号固定的分配给它们,以便于让所以的用户的了解,与之建立联系;

另一类为登记端口号(1024~49151),为那些不知名的应用程序使用;

(2)客户机使用的端口号:

也称为短暂端口号,由于这类端口仅仅在客户进程进行时才动态选择,留给客户进程短暂使用,当通信结束后,刚才使用过的客户端口号不复存在,可以继续供其他客户进程使用;

到此这篇关于java实现TCP socket和UDP socket的文章就介绍到这了,更多相关java实现TCP socket和UDP socket内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 实现了基于TCP的Java Socket编程实例代码

    实现了基于TCP的Java Socket编程,功能很简单:客户端向服务器端输出一名话"connect",服务器端接收输出到控制台并向客户端输出一名话"Hello",客户端接收并输出. 1.服务器端 复制代码 代码如下: package javase.net.socket; import java.io.DataInputStream;  import java.io.DataOutputStream;  import java.io.IOException;  im

  • Java基于Tcp协议的socket编程实例

    本文实例讲述了Java基于Tcp协议的socket编程方法,分享给大家供大家参考.具体分析如下: 以下是一对一的通信编程实现,后续会继续学习一个服务器监听多个客户端的实现. 这里用到的主要步骤如下: 第一步:以特定端口(如4800)新建socket对象 第二步:以系统输入设备构造BufferedReader对象,该对象用于接收系统键盘输入的字符 第三步:以socket对象 得到输出流来构造PrintWriter 第四步:以socket对象得到输入流来构造相应的BufferedReader对象,该

  • java实现基于UDP协议网络Socket编程(C/S通信)

    一.前言:认识UDP UDP,全称User Datagram Protocol(用户数据报协议),是Internet 协议集支持一个无连接的传输协议.UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法. UDP主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成,提供面向报文的简单不可靠信息传送服务.UDP 协议基本上是IP协议与上层协议的接口,适用端口分别运行在同一台设备上的多个应用程序. 二.UDP的特点(与TCP相比) 正是UDP提供不可靠服务

  • java实现基于Tcp的socket聊天程序

    对于步入编程行业不深的初学者或是已经有所领会的人来说,当学习一项新的技术的时候,非常渴望有一个附上注释完整的Demo.本人深有体会,网上的例子多到是很多,但是很杂不完整,写代码这种东西来不得半点马虎,要是错了一点,那也是运行不了的.这对于初学者来说更加的头疼,因为他根本不知道错在哪里,盲目的改只能错上加错.最后不得不去找找看看有没有能够直接运行的例子再加以模仿. 下面是博主在学习Java的socket时写的一个完整的例子,并且带上了完整的注释.它是一个简单的聊天程序,但是它可以设置任意多用户同时

  • java实现一个简单TCPSocket聊天室功能分享

    本文实例为大家分享了java实现TCPSocket聊天室功能的相关代码,供大家参考,具体内容如下 1.TCPserver.java import java.net.*; import java.io.*; import java.util.*; import java.util.concurrent.*; public class TCPserver{ private static final int SERVERPORT = 8888; private ServerSocket MyServe

  • java Socket UDP实例详解

    UDP编程示例 服务器端: package socket; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UDPServer { public static void main(String[] args) throws IOException { byte[] buf

  • Java实现Socket的TCP传输实例

    本文实例讲述了Java实现Socket的TCP传输.分享给大家供大家参考.具体分析如下: 客户端发数据到服务端 * Tcp传输,客户端建立的过程. * 1,创建tcp客户端socket服务.使用的是Socket对象. * 建议该对象一创建就明确目的地.要连接的主机. * 2,如果连接建立成功,说明数据传输通道已建立. * 该通道就是socket流 ,是底层建立好的. 既然是流,说明这里既有输入,又有输出. * 想要输入或者输出流对象,可以找Socket来获取. * 可以通过getOutputSt

  • Java通过 Socket 实现 TCP服务端

    1 Java Socket简介 所谓socket 通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过"套接字"向网络发出请求或者应答网络请求.Socket和ServerSocket类库位于Java.NET包中.ServerSocket用于服务器端,Socket是建立网络连接时使用的.在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话.对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或

  • Java基于socket服务实现UDP协议的方法

    本文实例讲述了Java基于socket服务实现UDP协议的方法.分享给大家供大家参考.具体如下: 示例1: 接收类: package com.socket.demo; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class UDPReceiveDemo { public static void main(String[] args) throw

  • java实现TCP socket和UDP socket的实例

    目录 概述 传输层概述 TCP套接字编程 大致过程 详细过程 UDP套接字编程 补充 概述 我们在网络编程时,通常是让我们本地的应用程序和远程的应用程序进行通信,也就是分布式的进程之间的通信,比如我写的程序A和小明的程序B进行通信,我的程序运行时在本机就是一个进程,是有pid号的,小明的也是.那这两个程序是怎么通信的呢? 这就要理解网络分层的概念了,网络层实现的是主机到主机之间的通信,网络层的实现是ip协议,通过各自的ip地址就能实现远程数据传输,而网络层只是保证了主机A的数据能够到达主机B,并

  • Java基于TCP协议的Socket通信

    目录 简介 TCP简介 JAVA Socket简介 SocketImpl介绍 TCP 编程 构造ServerSocket 1.1 绑定端口 1.2 设定客户连接请求队列的长度 1.3 设定绑定的IP 地址 1.4 默认构造方法的作用 多线程示例 简介 TCP简介 TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 793定义.在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户

  • JAVA实现基于Tcp协议的简单Socket通信实例

    好久没写博客了,前段时间忙于做项目,耽误了些时间,今天开始继续写起~ 今天来讲下关于Socket通信的简单应用,关于什么是Socket以及一些网络编程的基础,这里就不提了,只记录最简单易懂实用的东西.  1.首先先来看下基于TCP协议Socket服务端和客户端的通信模型: Socket通信步骤:(简单分为4步) 1.建立服务端ServerSocket和客户端Socket 2.打开连接到Socket的输出输入流 3.按照协议进行读写操作 4.关闭相对应的资源 2.相关联的API: 1.首先先来看下

  • Java基于TCP协议socket网络编程的文件传送的实现

    先了解一下socket基本概念 socket也叫套接字: 是指在网路中不同主机上的应用进程之间,进行双向通信的端点的抽象. 简单理解就是: 两个主机之间要通信,就需要知道彼此的ip,端口号等信息,而一台主机这些信息的集合: 就可以理解为一个端点,即为套接字 双方通过套接字作为一种坐标,建立信息通道,形成连接(两点连接一条直线) 简单理解了套接字的概念后,来看看如何通过java socket编程来实现 两台主机文件的接收与发送: 代码如下: 发送方: import java.io.*; impor

  • Java 基于TCP Socket 实现文件上传

    文件上传过程一个单向Socket通信过程.客户端通过文件输入流读取文件,然后从Socket获取输出流写入数据.服务端从Socket中获得输入流,然后写入文件输出流,写入数据完成则上传完成. 服务端UploadServer: public class UplaodServer { public static void main(String []args){ try( // 创建一个ServerSocket监听8080端口的请求 // ServerSocket 实现了 AutoCloseable接

  • java 基础知识之网络通信(TCP通信、UDP通信、多播以及NIO)总结

    java 基础知识之网路通信总结 在这篇文章里,我们主要讨论如何使用Java实现网络通信,包括TCP通信.UDP通信.多播以及NIO. TCP连接 TCP的基础是Socket,在TCP连接中,我们会使用ServerSocket和Socket,当客户端和服务器建立连接以后,剩下的基本就是对I/O的控制了. 我们先来看一个简单的TCP通信,它分为客户端和服务器端. 客户端代码如下: 简单的TCP客户端 import java.net.*; import java.io.*; public class

  • 浅谈java的TCP和UDP编程(附实例讲解)

    TCP 客户端: import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class MyClient { public static void main(String[] args) throws Exception{ Socket socket = null; BufferedReader in = n

  • Java Socket编程心跳包创建实例解析

    1.什么是心跳包? 心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包. 用来判断对方(设备,进程或其它网元)是否正常运行,采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经离线.用于检测TCP的异常断开.基本原因是服务器端不能有效的判断客户端是否在线,也就是说,服务器无法区分客户端是长时间在空闲,还是已经掉线的情况.所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已.代码就是每隔几分

  • Linux网络编程之UDP Socket程序示例

    在网络传输协议中,TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯定确认的信号,发送端如果收到接收端肯定确认的信号,就会继续发送其他的数据,如果没有,它就会重新发送. 相对而言,UDP协议则是一种无连接的,不可靠的数据报(SOCK_DGRAM)传输服务.使用UDP套接口不用建立连接,服务端在调用socket()生成一个套接字并调用bind()绑定端口后就可

随机推荐