在现有的网络中,网络通讯的方式主要有两种:

TCP(传输控制协议)方式

UDP(用户数据报协议)方式

在网络通讯中,TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。

而UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得。

这两种传输方式都是实际的网络编程中进行使用,重要的数据一般使用TCP方式进行数据传输,而大量的非核心数据则都通过UDP方式进行传递,在一些程序中甚至结合使用这两种方式进行数据的传递。

由于TCP需要建立专用的虚拟连接以及确认传输是否正确,所以使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些。

无论使用TCP方式还是UDP方式进行网络通讯,网络编程都是由客户端和服务器端组成当然,B/S结构的编程中只需要实现服务器端即可。所以,下面介绍网络编程的步骤时,均以C/S结构为基础进行介绍。

网络编程技术

1、客户端网络编程步骤

客户端(Client)是指网络编程中首先发起连接的程序,客户端一般实现程序界面和基本逻辑实现,在进行实际的客户端编程时,无论客户端复杂还是简单,以及客户端实现的方式,客户端的编程主要由三个步骤实现:

建立网络连接

客户端网络编程的第一步都是建立网络连接。在建立网络连接时需要指定连接到的服务器的IP地址和端口号,建立完成以后,会形成一条虚拟的连接,后续的操作就可以通过该连接实现数据交换了。

交换数据

连接建立以后,就可以通过这个连接交换数据了。交换数据严格按照请求响应模型进行,由客户端发送一个请求数据到服务器,服务器反馈一个响应数据给客户端,如果客户端不发送请求则服务器端就不响应。根据逻辑需要,可以多次交换数据,但是还是必须遵循请求响应模型。

关闭网络连接

在数据交换完成以后,关闭网络连接,释放程序占用的端口、内存等系统资源,结束网络编程。

在实际实现时,步骤2会出现重复,在进行代码组织时,由于网络编程是比较耗时的操作,所以一般开启专门的现场进行网络通讯。

2、服务器端网络编程步骤

服务器端(Server)是指在网络编程中被动等待连接的程序,服务器端一般实现程序的核心逻辑以及数据存储等核心功能。服务器端的编程步骤和客户端不同,是由四个步骤实现,依次是:

监听端口

服务器端属于被动等待连接,所以服务器端启动以后,不需要发起连接,而只需要监听本地计算机的某个固定端口即可。

这个端口就是服务器端开放给客户端的端口,服务器端程序运行的本地计算机的IP地址就是服务器端程序的IP地址。

获得连接

当客户端连接到服务器端时,服务器端就可以获得一个连接,这个连接包含客户端的信息,例如客户端IP地址等等,服务器端和客户端也通过该连接进行数据交换。

一般在服务器端编程中,当获得连接时,需要开启专门的线程处理该连接,每个连接都由独立的线程实现。

交换数据

服务器端通过获得的连接进行数据交换。服务器端的数据交换步骤是首先接收客户端发送过来的数据,然后进行逻辑处理,再把处理以后的结果数据发送给客户端。简单来说,就是先接收再发送,这个和客户端的数据交换数序不同。

其实,服务器端获得的连接和客户端连接是一样的,只是数据交换的步骤不同。

当然,服务器端的数据交换也是可以多次进行的。

在数据交换完成以后,关闭和客户端的连接。

关闭连接

当服务器程序关闭时,需要关闭服务器端,通过关闭服务器端使得服务器监听的端口以及占用的内存可以释放出来,实现了连接的关闭。

TCP方式是需要建立连接的,对于服务器端的压力比较大,而UDP是不需要建立连接的,对于服务器端的压力比较小罢了。

Java网络编程技术

和网络编程有关的基本API位于java.net包中,该包中包含了基本的网络编程实现,该包是网络编程的基础。该包中既包含基础的网络编程类,也包含封装后的专门处理WEB相关的处理类。

InetAddress类

该类的功能是代表一个IP地址,并且将IP地址和域名相关的操作方法包含在该类的内部。

先来个Demo

publicstaticvoidmain(String[] args)throwsIOException {

try{

//使用域名创建对象

InetAddress address=InetAddress.getByName("www.163.com");

System.out.println(address);

//使用ip创建对象

InetAddress address2=InetAddress.getByName("222.184.115.167");

System.out.println(address2);

//获得本机地址对象

InetAddress address3 = InetAddress.getLocalHost();

System.out.println(address3);

//获得对象中存储的域名

System.out.println("域名:"+address3.getHostName());

//获得对象中存储的ip地址

System.out.println("IP地址:"+address3.getHostAddress());

} catch(Exception e) {

// TODO: handle exception

}

}

由于该代码中包含一个互联网的网址,所以运行该程序时需要联网,否则将产生异常。

在后续的使用中,经常包含需要使用InetAddress对象代表IP地址的构造方法,当然,该类的使用不是必须的,也可以使用字符串来代表IP地址进行实现。

TCP编程

在Java语言中,对于TCP方式的网络编程提供了良好的支持,在实际实现时,以java.net.Socket类代表客户端连接,以java.net.ServerSocket类代表服务器端连接。在进行网络编程时,底层网络通讯的细节已经实现了比较高的封装,所以在程序员实际编程时,只需要指定IP地址和端口号码就可以建立连接了。正是由于这种高度的封装,一方面简化了Java语言网络编程的难度,另外也使得使用Java语言进行网络编程时无法深入到网络的底层,所以使用Java语言进行网络底层系统编程很困难,具体点说,Java语言无法实现底层的网络嗅探以及获得IP包结构等信息。但是由于Java语言的网络编程比较简单,所以还是获得了广泛的使用。

在使用TCP方式进行网络编程时,需要按照前面介绍的网络编程的步骤进行,下面分别介绍一下在Java语言中客户端和服务器端的实现步骤。

在客户端网络编程中,首先需要建立连接,在Java API中以java.net.Socket类的对象代表网络连接,所以建立客户端网络连接,也就是创建Socket类型的对象,该对象代表网络连接

// socket1实现的是连接到IP地址是192.168.1.103的计算机的10000号端口

Socket socket1 = newSocket("192.168.1.103",10000);

// socket2实现的是连接到域名是www.sohu.com的计算机的80号端口

Socket socket2 = newSocket("www.sohu.com",80);

底层网络如何实现建立连接,对于程序员来说是完全透明的。如果建立连接时,本机网络不通,或服务器端程序未开启,则会抛出异常。

连接一旦建立,则完成了客户端编程的第一步,紧接着的步骤就是按照“请求-响应”模型进行网络数据交换,在Java语言中,数据传输功能由Java IO实现,也就是说只需要从连接中获得输入流和输出流即可,然后将需要发送的数据写入连接对象的输出流中,在发送完成以后从输入流中读取数据即可。

//获得输出流

OutputStream outputStream = socket1.getOutputStream();

//获得输入流

InputStream inputStream=socket1.getInputStream();

这里获得的只是最基本的输出流和输入流对象,还可以根据前面学习到的IO知识,使用流的嵌套将这些获得到的基本流对象转换成需要的装饰流对象,从而方便数据的操作。

最后当数据交换完成以后,关闭网络连接,释放网络连接占用的系统端口和内存等资源,完成网络操作,示例代码如下:

socket1.close();

以上就是最基本的网络编程功能介绍。

接下来写个客户端的Demo,程序在客户端发送字符串到服务器,并将服务器端的反馈显示到控制台,数据交换只进行一次,当数据交换进行完成以后关闭网络连接,程序结束。

先来客户端的代码

importjava.io.InputStream;

importjava.io.OutputStream;

importjava.net.Socket;

publicclassClient {

publicstaticvoidmain(String[] args) {

Socket socket = null;

InputStream is = null;

OutputStream os = null;

try{

String msg = "Hello";

String ip = "localhost";

intport =9898;

// 建立连接

socket = newSocket(ip, port);

// 发送数据

os = socket.getOutputStream();

os.write(msg.getBytes());

// 接收数据

is = socket.getInputStream();

byteb[]=newbyte[1024];

intn =is.read(b);

System.out.println(newString(b,0,n));

} catch(Exception e) {

// TODO: handle exception

e.printStackTrace();

} finally{

try{

//关闭连接和流

is.close();

os.close();

socket.close();

} catch(Exception e2) {

// TODO: handle exception

e2.printStackTrace();

}

}

}

}

代码中建服务器端的代码:

publicclassServer {

publicstaticvoidmain(String[] args) {

ServerSocket serverSocket=null;

Socket socket=null;

InputStream is =null;

OutputStream os =null;

try{

serverSocket = newServerSocket(9898);

socket = serverSocket.accept();

is = socket.getInputStream();

byteb[] =newbyte[1024];

intn = is.read(b);

System.out.println("客户端发送了:"+newString(b,0,n));

os = socket.getOutputStream();

os.write("接收成功!".getBytes());

} catch(Exception e) {

// TODO: handle exception

e.printStackTrace();

}finally{

try{

is.close();

os.close();

socket.close();

serverSocket.close();

} catch(Exception e2) {

// TODO: handle exception

}

}

}

}

先运行服务器端,然后运行客户端,服务器接收到数据将数据打印出来之后再返回数据到客户端,客户端打印出来

在该示例代码中建立了一个监听当前计算机9898号端口的服务器端Socket连接,然后获得客户端发送过来的连接,如果有连接到达时,读取连接中发送过来的内容,并将发送的内容在控制台进行输出,输出完成以后将客户端发送的内容再反馈给客户端。最后关闭流和连接对象,结束程序。

在服务器端程序编程中,由于服务器端实现的是被动等待连接,所以服务器端编程的第一个步骤是监听端口,也就是监听是否有客户端连接到达。实现服务器端监听的代码为:

// 该代码实现的功能是监听当前计算机的9898号端口,如果在执行该代码时,

// 10000号端口已经被别的程序占用,那么将抛出异常。否则将实现监听。

serverSocket = newServerSocket(9898);

服务器端编程的第二个步骤是获得连接。该步骤的作用是当有客户端连接到达时,建立一个和客户端连接对应的Socket连 接对象,从而释放客户端连接对于服务器端端口的占用。通过获得连接,使得客户端的连接在服务器端获得了保持,另外使得服务器端的端口释放出来,可以继续等待其它的客户端连接。 实现获得连接的代码是:

socket = serverSocket.accept();

该代码实现的功能是获得当前连接到服务器端的客户端连接。需要说明的是accept和前面IO部分介绍的read方法一样,都是一个阻塞方法,也就是当无连接时,该方法将阻塞程序的执行,直到连接到达时才执行该行代码。另外获得的连接会在服务器端的该端口注册,这样以后就可以通过在服务器端的注册信息直接通信,而注册以后服务器端的端口就被释放出来,又可以继续接受其它的连接了。

连接获得以后,后续的编程就和客户端的网络编程类似了,这里获得的Socket类型的连接就和客户端的网络连接一样了,只是服务器端需要首先读取发送过来的数据,然后进行逻辑处理以后再发送给客户端,也就是交换数据的顺序和客户端交换数据的步骤刚好相反。这部分的内容和客户端很类似。

--------------------------

上面这个示例只是演示了网络编程的基本步骤以及各个功能方法的基本使用,只是为网络编程打下了一个基础,下面将就几个问题来深入介绍网络编程深层次的一些知识。

1.如何复用Socket连接?

拨通一次电话以后多次对话,这就是复用客户端连接。

建立连接以后,将数据交换的逻辑写到一个循环中,只要循环不结束则连接就不会被关闭,按照这种思路,可以改造一下上面的代码,让该程序可以在建立连接一次以后,发送三次数据,当然这里的次数也可以是多次

现在看下新的服务器代码和客户端代码:

importjava.io.InputStream;

importjava.io.OutputStream;

importjava.net.ServerSocket;

importjava.net.Socket;

/**

* 服务器代码

* */

publicclassServer {

publicstaticvoidmain(String[] args) {

ServerSocket serverSocket = null;

Socket socket = null;

InputStream is = null;

OutputStream os = null;

try{

serverSocket = newServerSocket(9898);

socket = serverSocket.accept();

is = socket.getInputStream();

os = socket.getOutputStream();

byteb[] =newbyte[1024];

for(inti =0; i <3; i++) {

intn = is.read(b);

os.write(("客户端发送的内容:"+newString(b,0, n)).getBytes());

}

} catch(Exception e) {

// TODO: handle exception

e.printStackTrace();

} finally{

try{

is.close();

os.close();

socket.close();

serverSocket.close();

} catch(Exception e2) {

// TODO: handle exception

}

}

}

}

再看下新的客户端代码:

importjava.io.InputStream;

importjava.io.OutputStream;

importjava.net.Socket;

/**

* 客户端代码

* */

publicclassClient {

publicstaticvoidmain(String[] args) {

Socket socket = null;

InputStream is = null;

OutputStream os = null;

try{

String msg[] = { "one","two","three"};

String ip = "localhost";

intport =9898;

// 建立连接

socket = newSocket(ip, port);

// 发送数据

os = socket.getOutputStream();

// 接收数据

is = socket.getInputStream();

byteb[] =newbyte[1024];

for(inti =0; i

os.write(msg[i].getBytes());

intn = is.read(b);

System.out.println(newString(b,0, n));

}

} catch(Exception e) {

// TODO: handle exception

e.printStackTrace();

} finally{

try{

// 关闭连接和流

is.close();

os.close();

socket.close();

} catch(Exception e2) {

// TODO: handle exception

e2.printStackTrace();

}

}

}

}

上面的代码虽然比较简单,但是通用性比较差。

在该程序中,比较明显的体现出了“请求-响应”模型,也就是在客户端发起连接以后,首先发送字符串“First”给服务器端,服务器端输出客户端发送的内容“First”,然后将客户端发送的内容再反馈给客户端,这样客户端也输出服务器反馈“First”,这样就完成了客户端和服务器端的一次对话

三次会话的过程一样,在这个过程中,每次都是客户端程序首先发送数据给服务器端,服务器接收数据以后,将结果反馈给客户端,客户端接收到服务器端的反馈,从而完成一次通讯过程。

2、如何使服务器端支持多个客户端同时工作?

一个服务器端一般都需要同时为多个客户端提供通讯,如果需要同时支持多个客户端,则必须使用前面介绍的线程的概念。简单来说,也就是当服务器端接收到一个连接时,启动一个专门的线程处理和该客户端的通讯。

改造之后的服务器代码,可以接收多个客户端的数据。

在该示例代码中,实现了一个while形式的死循环,由于accept方法是阻塞方法,所以当客户端连接未到达时,将阻塞该程序的执行,当客户端到达时接收该连接,并启动一个新的LogicThread线程处理该连接,然后按照循环的执行流程,继续等待下一个客户端连接。这样当任何一个客户端连接到达时,都开启一个专门的线程处理,通过多个线程支持多个客户端同时处理。

/**

* 支持多客户端的服务器代码

* */

publicclassServer {

publicstaticvoidmain(String[] args) {

ServerSocket serverSocket = null;

Socket socket = null;

try{

serverSocket = newServerSocket(9898);

while(true) {

socket = serverSocket.accept();

// 启动线程

// 实现接收客户端连接,然后开启专门的逻辑线程处理该连接,

// LogicThread类实现对于一个客户端连接的逻辑处理,将处理的逻辑放置在该类的run方法中。

newLogicThread(socket);

}

} catch(Exception e) {

// TODO: handle exception

e.printStackTrace();

} finally{

try{

socket.close();

serverSocket.close();

} catch(Exception e2) {

// TODO: handle exception

}

}

}

staticclassLogicThreadextendsThread {

Socket socket = null;

publicLogicThread(Socket socket) {

this.socket = socket;

start();

}

@Override

publicvoidrun() {

byteb[] =newbyte[1024];

InputStream is = null;

OutputStream os = null;

try{

is = socket.getInputStream();

os = socket.getOutputStream();

intn = is.read(b);

os.write(("客户端发送的内容:"+newString(b,0, n)).getBytes());

} catch(Exception e) {

// TODO: handle exception

e.printStackTrace();

} finally{

try{

is.close();

os.close();

socket.close();

} catch(Exception e2) {

// TODO: handle exception

}

}

}

}

}

这里的示例还只是基础的服务器端实现,在实际的服务器端实现中,由于硬件和端口数的限制,所以不能无限制的创建线程对象,而且频繁的创建线程对象效率也比较低,所以程序中都实现了线程池来提高程序的执行效率。

这里简单介绍一下线程池的概念,线程池(Thread pool)是池技术的一种,就是在程序启动时首先把需要个数的线程对象创建好,例如创建5000个线程对象,然后当客户端连接到达时从池中取出一个已经创建完成的线程对象使用即可。当客户端连接关闭以后,将该线程对象重新放入到线程池中供其它的客户端重复使用,这样可以提高程序的执行速度,优化程序对于内存的占用等。

关于基础的TCP方式的网络编程就介绍这么多,下面一章介绍UDP方式的网络编程在Java语言中的实现。

java中no1_【Java】-- 网络编程のNo.1相关推荐

  1. 《亿级流量JAVA高并发与网络编程实战》笔记--------更新中

    <亿级流量JAVA高并发与网络编程实战>笔记 第一章 高并发概述 "高并发技术" 是一个广义的概念,是指一种高效的地实现并发需求的解决方案,是技术领域的名称,可以包含架 ...

  2. 20165310 Java实验五《网络编程与安全》

    20165310 Java实验五<网络编程与安全> 任务一 题目:①编写MyBC.java实现中缀表达式转后缀表达式的功能:②编写MyDC.java实现从上面功能中获取的表达式中实现后缀表 ...

  3. Java并发编程实战_阿里P9整理分享的亿级流量Java高并发与网络编程实战PDF

    前言 为了帮助初级开发者快速掌握高并发.网络编程.微服务.海量数据的处理这些实用技术,本文以"理论+范例"的形式对各个知识点进行了详细的讲解,力争让读者在实践中快速掌握相关知识. ...

  4. java nio 客户端_Java网络编程:Netty框架学习(二)---Java NIO,实现简单的服务端客户端消息传输...

    概述 上篇中已经讲到Java中的NIO类库,Java中也称New IO,类库的目标就是要让Java支持非阻塞IO,基于这个原因,更多的人喜欢称Java NIO为非阻塞IO(Non-Block IO), ...

  5. Java学习——Day14:网络编程

    7.1 网络编程概述 Java是 Internet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序. Java提供的网络类库,可以实现无痛的网络连接,联网的 ...

  6. 阿里P9整理分享的亿级流量Java高并发与网络编程实战PDF

    前言 有人调侃我们说: 程序员不如送外卖.送外卖是搬运食物,自己是搬运代码,都不产出新的东西-- 透支体力,又消耗健康,可替代性极强,30岁之后就要面临被优化的危险-- 想跳槽,但是更高的平台难进,同 ...

  7. Java语言进阶:网络编程入门

    Java语言进阶:网络编程 网络编程入门 C/S C/S结构 :全称为Client/Server结构,是指客户端和服务器结构.常见程序有QQ.迅雷等软件. 特点: 客户端和服务器是分开的,需要下载客户 ...

  8. Java 中的面向数据编程

    近年来, Amber项目为 Java 带来了许多新特性-- 局部变量类型推断. 文本块. 记录类. 封印类. 模式匹配 等等.虽然这些特性都是独立的,但也可以组合在一起使用.具体地说,记录类.封印类和 ...

  9. Java面试知识点:网络编程

    问题:Java面试知识点:网络编程 答案: 1.InetAddress 代码如下: package com.xy;import java.net.InetAddress; import java.ne ...

  10. 17、Java中的面向对象的编程思想

    Java中的面向对象的编程思想 作者:韩茹 公司:程序咖(北京)科技有限公司 程序咖:IT职业技能评测平台 网址:https://www.chengxuka.com 任务 1. 面向对象 2. 面向过 ...

最新文章

  1. 关于学习Python的一点学习总结(39->导入模块)
  2. java自动生成代码原理_原来这就是Java代码生成器的原理啊,太简单了
  3. 查看docker镜像的dockerfile脚本json信息
  4. Two sum(给定一个无重复数组和目标值,查找数组中和为目标值的两个数,并输出其下标)...
  5. 69-Python的匿名函数1
  6. diff 比较文件异同命令
  7. SVN安装-Subversive Plug-In 和Subversive SVN Connectors
  8. linux命令行大于号、小于号、双大于号、双小于号
  9. lighttpd 之十二 网络请求服务响应流程
  10. 蒂姆-库克于2010年5月14日在奥本大学毕业典礼上发表的演讲全文
  11. 总结一下vue添加收藏取消收藏功能
  12. “似水无形” 的小程序化
  13. 高等数学笔记-苏德矿-第九章-重积分(Ⅱ)-三重积分
  14. 学习ARM开发(11)
  15. 硬件ecc和软件ecc
  16. linux avg 强力卸载,彻底卸载AVG维护清理软件
  17. excel高级筛选怎么用_如何用excel在筛选状态下怎么复制粘贴?
  18. 从 PC 解锁 Android 手机的 6 种有效方法
  19. ESD器件的主要性能参数
  20. 程序员手把手教你Mac M1Pro的java开发环境安装--jdk、git、maven、及tomcat

热门文章

  1. MySQL编程技巧_MySQL学习笔记---MySQL开发技巧
  2. php mysql 分行执行,php执行mysql存储及执行脚本
  3. abb限位开关已打开drv1_Telemecanique传感器限位开关产品系列
  4. java 双向链表_23张图!万字详解「链表」,从小白到大佬
  5. 没有bug队——加贝——Python 练习实例 19,20
  6. MDL锁导致mysql夯住_MySQL MetaData Lock 案例分享
  7. 二元一次函数最值问题_初二上学期,一次函数方案设计最值问题,两类题目解题思路不一样...
  8. excel在线_功能强大的纯前端 Excel 在线表格: Luckysheet
  9. linux找出重复数字,C语言笔试经典-查找多位数重复数字以及次数
  10. MATLAB求线性代数的参数范围,MATLAB科学计算04(线性代数问题求解一)