Java高并发网络编程(一)

一、OSI网络七层模型

因特网是一个极为复杂的网络,分层有助于我们对网络的理解 。分层也是一种标准,为了使不同厂商的计算机能够互相通信,以便在更大范围内建立计算机网络,有必要建立一个国际范围的网络体系结构标准。

ISO组织制定了OSI网络七层模型

应用层
表示层
会话层
传输层
网络层
链路层
物理层

而因特网只用到了五层

应用层
传输层
网络层
链路层
物理层

低三层:

屏蔽底层网络的复杂性

物理层:使原始的数据比特流能在物理介质上传输。

数据链路层:通过校验、确认和反馈重发等手段,形成稳定的数据链路。(01010101)

网络层:进行路由选择和流量控制。(IP协议)

传输层:提供可靠的端口到端口的数据传输服务(TCP/UDP协议)。

高三层:

会话层:负责建立、管理和终止进程之间的会话和数据交换。

表示层:负责数据格式转换、数据加密与解密、压缩与解压缩等。

应用层:为用户的应用进程提供网络服务。

网络通信协议

二、传输层控制协议TCP

传输层控制协议(TCP)是Internet一个重要的传输层协议。TCP提供面向连接、可靠、有序、字节流传输服务。应用程序在使用TCP之前,必须先建立TCP连接。

1.TCP握手机制

检测网络是否通畅

三、用户数据报协议UDP

用户数据报协议UDP是Internet传输层协议。提供无连接、不可靠、数据尽力传输服务。

TCP和UDP比较

四、Socket

1.Scoket概述

网络应用程序由成对的进程组成,这些进程通过网络相互发送报文。在一对进程之间的通信会话场景中,发起通信的进程被标识为客户,在会话开始时等待联系的进程是服务器。进程通过一个称为套接字的软件接口向网络发送报文和从网络接收报文。套接字是同一台主机内应用层与传输层之间的接口,由于该套接字是建立网络应用程序的可编程接口,因此套接字也称为应用程序和网路之间的应用程序编程接口(API)。应用程序开发者可以控制套接字在应用层端的一切,但是对该套接字的运输层端几乎没有控制权,因此网络编程实际上就是Socket编程

IP地址:InetAddress

  • 唯一的标识Internet上的计算机
  • 本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost
  • 不易记忆

端口号标识正在计算机上运行的进程(程序)

  • 不同的进程有不同的端口号
  • 被规定为一个16位的整数0~65535。其中,0~1023被预先定义的服务通信占用(如MySql占用端口3306,http占用端口80等)。除非我们需要访问这些特殊服务,否则,应该使用1024~65535这些端口中的某一个进行通信,以免发生端口冲突。

端口号与IP地址的组合得出一个网络套接字

Internet应用最广的网络应用编程接口,实现与3种底层协议接口:

  • 数据报类型套接字SOCK_DGRAM(面向UDP接口)
  • 流式套接字SOCK_STREAM(面向TCP接口)
  • 原始套接字SOCK_RAW(面向网络层协议接口IP、ICMP等)

主要socket API及其调用过程

2.Java中的Socket编程

客户端

public class SocketClient {

    public void client() {
        Socket sc = null;
        OutputStream os = null;
        InputStream is = null;
        try {
            sc = new Socket(InetAddress.getByName("127.0.0.1"), 9092);
            os = sc.getOutputStream();
            os.write("我是客户端,我向你发送消息了".getBytes());
            sc.shutdownOutput(); // 显式的告诉服务端发送完毕

            is = sc.getInputStream();
            byte[] b = new byte[30];
            int len;
            while ((len = is.read(b)) != -1) {
                String str = new String(b, 0, len);
                System.out.println(str);
            }

        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {

            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (sc != null) {
                try {
                    sc.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        SocketClient client = new SocketClient();
        client.client();
    }
}

当Client程序需要从Server端获取信息及其他服务时,应创建一个Socket对象

构造函数

new Socket(InetAddress.getByName("127.0.0.1"), 9092)会打开一个套接字

一旦套接字被打开,java.net.Socket类中的getInputStream方法就会返回一个InputStream对象,该对象可以像其他任何流一样使用,接收另一端传来的数据

getOutPutStream则是输出流,可以传给另一端

套接字离不开IP地址, Java中有IP相关的类

InetAddress类没有提供公共的构造方法,而是提供了两个静态方法来获取InetAddress实例

InetAddress有如下常用方法:

服务器端

public class SocketServer {

    public void server() {
        ServerSocket ss = null;
        Socket s = null;
        InputStream is = null;
        OutputStream os = null;
        try {
            ss = new ServerSocket(9092);
            s = ss.accept();
            is = s.getInputStream();
            /**
             * 1、 read()方法,这个方法从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。 2、read(byte[] b,int
             * off,int len)方法,将输入流中最多 len 个数据字节读入 byte 数组。尝试读取len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。 3、read(byte[]
             * b)方法,从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。
             */
            byte[] b = new byte[30];
            int len;
            while ((len = is.read(b)) != -1) {
                /**
                 * new String(bytes, offset, length) bytes为要解译的字符串; offset为要解译的第一个索引,比如从0开始就是从字符串bytes的第一个字符开始;
                 * length为要解译的字符串bytes的长度
                 */
                String str = new String(b, 0, len);
                System.out.println(str);
            }
            os = s.getOutputStream();
            os.write("我是服务端,收到了你的信息".getBytes());

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (s != null) {
                try {
                    s.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (ss != null) {
                try {
                    ss.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        }
    }

    public static void main(String[] args) {
        SocketServer server = new SocketServer();
        server.server();
    }
}

服务器需随时待命,因为不知道客户端什么时候会发来请求,此时,我们需要使用ServerSocket,对应的是java.net.ServerSocket类

构造函数

new ServerSocket(9092)建立一个监听9092接口的服务器

ss.accept()告诉程序不停的等待,直到客户端连接到这个接口。一旦有人通过网络发送了正确的连接请求,并以此连接到了端口上,该方法就返回一个表示连接已经建立的Socket对象。

可以使用这个对象来得到输入流和输出流

原文地址:https://www.cnblogs.com/aidata/p/11521305.html

时间: 2024-10-09 11:37:37

Java高并发网络编程(一)的相关文章

Java高并发网络编程(四)Netty

在网络应用开发的过程中,直接使用JDK提供的NIO的API,比较繁琐,而且想要进行性能提升,还需要结合多线程技术. 由于网络编程本身的复杂性,以及JDK API开发的使用难度较高,所以在开源社区中,涌现出来了很多对JDK NIO进行封装.增强的网络编程框架,比如Netty.Mina等. 一.Netty简介 https://netty.io/ 官网 Netty是一个高性能.高可扩展性的异步事件驱动的网络应用程序框架,它极大简化了TCP和UDP客户端和服务器开发等网络编程. Netty重要的四个内容

Java高并发网络编程(三)NIO

从Java 1.4开始,Java提供了新的非阻塞IO操作API,用意是替代Java IO和Java Networking相关的API. NIO中有三个核心组件: Buffer缓冲区 Channel通道 Selector选择器 一.Buffer缓冲区 缓冲区本质上是一个可以写入数据的内存块(类似数组),然后可以再次读取.此内存块包含在NIO Buffer对象中,该对象提供了一组方法,可以更轻松地使用内存块. 相比较直接对数组的操作,BufferAPI更容易操作和管理. 使用Buffer进行数据写入

Java高并发网络编程(五)Netty应用

推送系统 一.系统设计 二.拆包和粘包 粘包.拆包表现形式 现在假设客户端向服务端连续发送了两个数据包,用packet1和packet2来表示,那么服务端收到的数据可以分为三种,现列举如下: 第一种情况,接收端正常收到两个数据包,即没有发生拆包和粘包的现象,此种情况不在本文的讨论范围内. 第二种情况,接收端只收到一个数据包,由于TCP是不会出现丢包的,所以这一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包.这种情况由于接收端不知道这两个数据包的界限,所以对于接收端来说很难处理.

Linux下高并发网络编程

1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时, 最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统 为每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄). 可使用ulimit命令查看系统允许当前用户进程打开的文件数限制: [[email protected] ~]$ ulimit -n 1024 这表示当前用户的每个进程最多允许同时打开1024个文件,这1024

Java高并发编程(一)

1.原子量级操作(读.++操作.写分为最小的操作量单位,在多线程中进行原子量级编程保证程序可见性(有序性人为规定)) 由于某些问题在多线程条件下:产生了竞争的问题,(例如:在多线程中一个简单的计数器增加)如果在程序中不采用同步的机制,那么在程序的运行结果中,多个线程在访问此资源时候,产生Racing.解决这个问题,采用某种方式阻止其他线程在该线程使用该变量的时候使用该变量 采用原子级操作:1.采用加锁的机制(最好的操作)2.Java.concurrent.atomic包包含一些原子量操作:Ato

Java学习之网络编程实例

转自:http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html 多谢分享 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在学习网络编程以前,很多初学者可能觉得网络编程是比较复杂的系统工程,需要了解很多和网络相关的基础知识,其实这些都不是很必需的.首先来问一个问题:你 会打手机吗?很多人可能说肯定会啊,不就是按按电话号码

Java高并发是不是你的菜??

自从JAVA5.0增加了最初由DougLea编写的高质量的.广泛使用的.并发实用程序util.concurrent并变成了JSR-166的新包之后,在Java内置所提供的类库中,就提供了越来越多的并发编程的实用工具类.学习并掌握这些技术对于专注于Java并发编程的开发人员来讲是基本的公里,随着Java版本的不断更新与改进,开发人员可以通过Java新版本所带来的新特性,无需从头重新编写并发程序工具类. 我们该学习Java并发嘛? 我们该如何学习Java并发? CPU这么多核了,我们如何更好的利用?

Java高并发的常见应对方案

Java高并发的常见应对方案 一.关于并发我们说的高并发是什么? 在互联网时代,高并发,通常是指,在某个时间点,有很多个访问同时到来. 高并发,通常关心的系统指标与业务指标? QPS:每秒钟查询量,广义的,通常指指每秒请求数 响应时间:从请求发出到收到响应花费的时间,例如:系统处理一个HTTP请求需要100ms,这个100ms就是系统的响应时间 带宽:计算带宽大小需关注两个指标,峰值流量和页面的平均大小 PV:综合浏览量(Page View),即页面浏览量或者点击量,通常关注在24小时内访问的页

Java高并发秒杀API之业务分析与DAO层

课程介绍 高并发和秒杀都是当今的热门词汇,如何使用Java框架实现高并发秒杀API是该系列课程要研究的内容.秒杀系列课程分为四门,本门课程是第一门,主要对秒杀业务进行分析设计,以及DAO层的实现.课程中使用了流行的框架组合SpringMVC+Spring+MyBatis,还等什么,赶快来加入吧! 第1章 课程介绍 本章介绍秒杀系统的技术内容,以及系统演示.并介绍不同程度的学员可以学到什么内容. 第2章 梳理所有技术和搭建工程 本章首先介绍秒杀系统所用框架和技术点,然后介绍如何基于maven搭建项