Java网络编程简明教程

网络编程

计算机网络相关概念

计算机网络是两台或更多的计算机组成的网络,同一网络内的任意两台计算机可以直接通信,所有计算机必须遵循同一种网络协议。

互联网

互联网是连接计算机网络的网络

互联网采取TCP/IP协议

其中最重要的两个协议是TCP协议和IP协议

IP地址和网关

IP地址用于唯一标识一个网络接口

IPv4采用32位地址

IPv4地址实际是一个二进制32位的整数,为了便于识别,用十六进制表示后可以分为4组数字,每组数字转换成十进制后用“.”隔开就是我们见到的IP地址:

IPv6采用128位地址

公网IP地址可以直接被访问

内网IP地址只能在内网访问

本机地址使用127.0.0.1

通常路由器或交换机有两个网卡(两个IP地址),分别连接两个不同的网络:

同一网络下的计算机可以直接通信,他们的网络号相同,网络号由IP地址和子掩码按组对齐做与运算得到:

不同网络下的计算机需要通过路由器或交换机网络设备间接通信,这样的网络设备叫做网关:

网关的作用是连接多个网络,负责把一个网络的数据包发送到另一个网络,过程叫做路由:

一台计算机的网络拥有IP地址,子网掩码和网关(路由器)三个关键配置:

域名

由于IP地址不便于记忆,通常使用域名来访问特定的服务,域名解析服务器DNS负责将域名翻译成对应的IP地址,客户端再根据IP地址访问服务器:

TCP/IP协议

IP协议是一个分组交换协议,不保证可靠传输,一个数据包通过IP协议传输会自动分成若干小的数据包然后通过网络进行传输

TCP(Transmission Control Protocol)协议是一个传输控制协议,建立再IP协议之上,IP协议负责传输数据包,TCP协议负责控制传输数据包;TCP协议传输之前需要先建立连接,然后才能传输数据,传输完成后断开连接;TCP协议是一个可靠传输协议,他通过接收确认,超时重传实现;TCP协议支持双向通信,双方可以同时传输和接收数据

UDP协议

UDP(User Datagram Protocol)协议是数据报文协议,不面向连接,不保证可靠传输,由于UDP协议传输效率高,通常用来传输视频等能容忍丢失部分数据的文件。

Socket

Socket通常称为套接字,用于应用程序之间建立远程连接,Socket内部通过TCP/IP协议进行数据传输,可以简单的理解为对IP地址和端口号的描述。Socket接口是由计算机操作系统提供的,编程语言提供对Socket接口调用的封装。通常计算机同时运行多个应用程序,仅仅有IP地址是无法确定由哪个应用程序接收数据,所以操作系统抽象出Socket接口,每个应用程序对应不同的socket(每个网络应用程序分配不同的端口号)。端口号的范围是0~65535,小于1024的端口需要管理员权限,大于1024的端口可以任意用户的应用程序打开。

Socket编程需要实现服务器端和客户端,因为这两个设备通讯时,需要知道对方的IP和端口号。通常服务器端有个固定的端口号,客户端直接通过服务器的IP地址和端口号进行访问服务器端,同时告知客户端的端口号,于是他们之间就可以通过socket进行通信。

TCP编程

TCP客户端

Java提供了Socket类ServerSocket类对计算机操作系统的Socket进行调用。客户端使用Socket(InetAddress, port)构造方法传入IP地址和端口号打开Socket,与远程服务区指定端口进行连接, 然后调用socket的getInputStream和getOutputStream方法获取输入和输出流就可以读写TCP的字节流:

// 连接远程服务器

Socket socket = new Socket(InetAddress, port);

// 读写字节流

InputStream in = socket.getInputStream();

OutputStream out = socket.getOutputStream();

TCP服务端

服务器端通过ServerSocket(port)构造方法传入端口号来监听指定的端口,然后通过accept()方法得到一个Socket对象与远程客户端建立连接,同样调用Socket对象的getInputStream和getOutputStream方法就可以读写字节流,服务器端完成传输后可以通过close()方法关闭远程连接和监听端口:

// 监听端口

ServerSocket serverSocket = new ServerSocket(port);

// 建立远程连接

Socket socket = serverSocket.accept();

// 读写字节流

InputStream in = socket.getInputStream();

OutputStream out = socket.getOutputStream();

// 关闭连接

socket.close();

// 关闭监听端口

serverSocket.close();

TCP编程实验

我们可以在本机做一个小实验,首先编写一个客户端的TCPClient类,通过Java提供的InetAddress类的getLoopbackAddress()方法获得localhost地址,然后使用Java的Socket类创建一个与本机8090端口的连接,再将读取字节流包装成一个BufferedReader对象、写入字节流包装成BufferedWriter对象。使用BufferedWriter写入一个“time”字符串并发送到本机的8090端口,再用BufferedReader读取本机8090端口返回的数据并打印出来。代码如下:

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.net.InetAddress;

import java.net.Socket;

import java.nio.charset.StandardCharsets;

public class TCPClient{

public static void main(String[] args) throws IOException{

// 获取本机地址,即“127.0.0.1”

InetAddress addr = InetAddress.getLoopbackAddress();

// 与本机8090端口建立连接

try (Socket sock = new Socket(addr, 8090)) {

// 将读写字节流包装成BufferedReader和BufferedWriter对象

try (BufferedReader reader = new BufferedReader(

new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8))) {

try (BufferedWriter writer = new BufferedWriter(

new OutputStreamWriter(sock.getOutputStream(), StandardCharsets.UTF_8))) {

// 写入“time”字符串

writer.write("time\n");

// 将写入内存缓冲区的数据立即发送

writer.flush();

// 读取本机8090端口返回的数据

String resp = reader.readLine();

System.out.println("Response: " + resp);

}

}

}

}

}

在相同包下写一个服务端的TCPServer类,利用Java的ServerSocket类监听8090端口并打印一句话“TCP server ready.”,然后用ServerSocket类的accept()方法与监听到的访问8090端口的客户端请求建立连接,然后和客户端一样包装读写字节流。服务端首先读取数据,如果读取到的数据是一个"time"字符串,则将当前时间信息返回给客户端,如果不是则返回一个“require data”字符串给客户端,最后关闭连接和关闭监听接口。

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.net.ServerSocket;

import java.net.Socket;

import java.nio.charset.StandardCharsets;

import java.time.LocalDateTime;

public class TCPServer{

public LocalDateTime currentTime(){

return LocalDateTime.now();

}

public static void main(String[] args) throws Exception{

// 监听8090端口

ServerSocket ss = new ServerSocket(8090);

System.out.println("TCP server ready.");

// 建立连接

Socket sock = ss.accept();

// 包装读写字节流

try (BufferedReader reader = new BufferedReader(

new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8))) {

try (BufferedWriter writer = new BufferedWriter(

new OutputStreamWriter(sock.getOutputStream(), StandardCharsets.UTF_8))) {

// 读取发送到服务端的数据

String cmd = reader.readLine();

// 如果数据是“time”字符串则将当前时间信息返回客户端

if ("time".equals(cmd)) {

writer.write(LocalDateTime.now().toString() + "\n");

// 将写入内存缓冲区的数据立即发送

writer.flush();

} else {

writer.write("require data\n");

writer.flush();

}

}

}

// 关闭连接

sock.close();

// 关闭监听端口

ss.close();

}

}

我们首先运行服务端TCPServer类的main方法,开始监听8090端口,并且Console打印出“TCP server ready.”,然后运行客户端TCPClient的main方法,我们得到Response信息,终端打印出了当前的时间信息:

如果我们先运行客户端的main方法,我们会得到一个异常ConnectException: Connection refused,因为服务端并没有开始监听8090端口,无法与客户端建立socket连接。

TCP多线程

服务端的一个ServerSocket可以同时和多个客户端建立连接进行双向通信,实现起来也很简单,在设置好监听端口后,在一个无限for循环中调用ServerSocket的accept()方法,返回与客户端新建的连接,再启动线程或者使用线程池来处理客户端的请求,这样就可以同时处理多个客户端的连接,代码如下:

public class TCPServer{

public static void main(String[] args) throws Exception{

@SuppressWarnings("resource")

ServerSocket ss = new ServerSocket(8090);

System.out.println("TCP server ready.");

for (;;) { // 无限for循环中返回客户端新建的连接

Socket sock = ss.accept();

// 设置线程要处理的任务

Runnable handler = new TimeHandler(sock);

// 使用Java提供的ExecutorService创建线程池

ExecutorService executor = Executors.newCachedThreadPool();

// 线程处理任务

executor.submit(handler);

// 任务处理完毕,关闭线程

executor.shutdown();

}

}

}

class TimeHandler implements Runnable{

Socket sock;

TimeHandler(Socket sock) {

this.sock = sock;

}

@Override

public void run(){

try (BufferedReader reader = new BufferedReader(

new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8))) {

try (BufferedWriter writer = new BufferedWriter(

new OutputStreamWriter(sock.getOutputStream(), StandardCharsets.UTF_8))) {

for (;;) {

String cmd = reader.readLine();

if ("q".equals(cmd)) {

writer.write("bye!\n");

writer.flush();

break;

} else if ("time".equals(cmd)) {

writer.write(LocalDateTime.now().toString() + "\n");

writer.flush();

} else {

writer.write("require data\n");

writer.flush();

}

}

}

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

this.sock.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

UDP编程

UDP协议不需要建立连接,可以直接发送和接收数据,UDP协议不保证可靠传输,使用Java提供的DatagramSocket的send()和receive()方法就可以发送和接收数据,UDP协议接收和发送数据没有IO流接口。

客户端

public class UDPClient{

public static void main(String[] args) throws Exception{

InetAddress addr = InetAddress.getLoopbackAddress();

try (DatagramSocket sock = new DatagramSocket()) { // 创建DatagramSocket对象

sock.connect(addr, 9090); // 设置要访问的服务端地址和端口

byte[] data = "time".getBytes(StandardCharsets.UTF_8);

DatagramPacket packet = new DatagramPacket(data, data.length); // 将字节流包装成DatagramPacket对象

sock.send(packet); // 发送数据

System.out.println("Data was sent.");

Thread.sleep(1000);

byte[] buffer = new byte[1024];

DatagramPacket resp = new DatagramPacket(buffer, buffer.length);

sock.receive(resp); // 接收数据

byte[] respData = resp.getData();

String respText = new String(respData, 0, resp.getLength(), StandardCharsets.UTF_8);

System.out.println("Response: " + respText);

}

}

}

服务端

public class UDPServer{

public LocalDateTime currentTime(){

return LocalDateTime.now();

}

public static void main(String[] args) throws Exception{

@SuppressWarnings("resource")

DatagramSocket ds = new DatagramSocket(9090); // 设置要监听的端口

System.out.println("UDP server ready.");

for (;;) {

// 接收数据:

byte[] buffer = new byte[1024];

DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

ds.receive(packet);

byte[] data = packet.getData();

String s = new String(data, StandardCharsets.UTF_8);

System.out.println("Packet received from: " + packet.getSocketAddress() + " " + s);

// 发送数据:

String resp = LocalDateTime.now().toString();

packet.setData(resp.getBytes(StandardCharsets.UTF_8));

ds.send(packet);

}

}

}

Email编程

电子邮件的一些基本概念:

MUA(Mail User Agent)发送和接收邮件所使用的邮件客户端,通常使用IMAP或POP3协议与服务器通信

MTA(Mail Transfer Agent) 通过SMTP协议发送、转发邮件

MDA(Mail Deliver Agent)将MTA接收到的邮件保存到磁盘或指定地方

SMTP协议(Simple Mail Transfer Protocol)是发送邮件使用的标准协议,建立在TCP协议之上,标准端口25,加密端口为465/587

POP3协议(Post Office Protocol version3) 是接收邮件使用的标准协议之一,建立在TCP协议之上,标准端口为110,加密端口为995

IMAP协议 (Internet Mail Access Protocol )是接收邮件使用的标准协议之一,和POP3协议的区别是IMAP协议允许用户创建文件夹,用户在本地的任何操作都自动同步到邮件服务器,准备端口为143,加密端口为993

Java提供了一个javax.mail包,可以很方便的实现发送和接收邮件,而不用去关系SMTP协议和POP3协议的原理,方法如下:

发送邮件首先创建一个Session对象,传入邮件服务器信息和用户名密码认证信息

Session session = Session.getInstance(props, new Authticator());

然后创建MimeMessage对象,封装邮件发件人地址、收件人地址,邮件主题,邮件正文等信息

MimeMessage message = new MimeMessage(session);

message.setFrom(new InternetAddress("from@email.com"));

message.setRecipient(Message.RecipientType.TO, new InternetAddress("to@email.com"));

message.setSubject("subject", "UTF-8");

message.setText("body", "UTF-8");

最后使用Transport工具类的send()方法发送邮件

Transport.send(message);

接收邮件首先创建Session对象,同样需要传入服务器信息和登录名密码认证

Session session = Session.getInstance(props, null);

然后创建Store对象,Store对象代表用户在服务器上的整个存储

Store store = new POP3SSLStore(session, url)

通过Store对象获取Folder对象,获取用户相应的文件夹,比如收件箱“INBOX”

Folder folder = store.getFolder("INBOX");

从Folder对象中获取所有的邮件

Message[] messages = folder.getMessage();

for (Message message : messages) { ... };

由于本文只是Java编程简明教程,对Email编程就不作过多的讲述,更多的功能可以参考JAVA MAIL相关API文档。

HTTP编程

HTTP协议(HyperText Transfer Protocol)又叫做超文本传输协议,它是基于TCP协议上的请求和响应协议,是目前使用最广泛的高级协议。最早的HTTP协议版本是HTTP 1.0,每一次请求,都会创建一个TCP连接,由于浏览器打开网页通常会请求不同的资源(例如图片,CSS等其他资源),创建TCP连接会有一定耗时,所以传输效率比较低;HTTP 1.1 则做出改进,多个HTTP请求可以通过一个TCP连接完成,效率得到提高;HTTP 2.0 同样也是多个请求通过一个TCP连接完成,但是浏览器发送一个请求后不需要等待服务器的响应就可以立刻发送后续的请求,服务器只要有了响应数据立刻返回,不关心请求的顺序,也就是说HTTP 2.0 不需要严格按照收到请求再响应的方式进行。

HTTP服务器用于处理HTTP请求,发送HTTP响应。在Java中,HTTP服务器通过JAVA EE的Servlet API定义,通常Servlet容器根据收到的HTTP请求信息创建一个Request对象,再创建一个Response对象用来向Web客户端发送响应,调用Servlet对象的service()方法处理Request和Response,具体参考Servlet教程。

HTTP客户端用于发送HTTP请求,接收HTTP响应。Java提供的java.net.HttpURLConnection类可以实现HTTP客户端功能:

发送GET请求

URL url = new URL("http://www.example.com/");

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

int code = conn.getResponseCode(); //获得响应代码

try (InputStream input = conn.getInputStream()) {

// 读取响应

}

conn.disconnect(); // 断开连接

发送POST请求

URL url = new URL("http://www.example.com/");

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("POST");

conn.setDoOutput(true); // 需要发送请求数据

byte[] postData = contentData.getBytes(StandardCharsets.UTF_8); // 将发送请求数据转换为数组

conn.setRequestProperty("Content-Type", contentType); // 设置请求Content-Type

conn.setRequestProperty("Content-Length", String.valueOf(postData.length)); 设置请求Content-Length

try (OutputStream output = conn.getOutputStream()){

output.write(postData); // 写入请求数据

}

int code = conn.getResponseCode(); // 获取响应代码

try (InputStream input = conn.getInputStream()) {

// 读取响应数据

}

conn.disconnect(); // 断开连接

总结

Java提供了Socket和ServerSocket类,让我们可以实现TCP/UDP协议的连接;Java还提供了MAIL API,我们可以实现基于SMTP/POP3协议的收发邮件功能;最后Java还提供了HttpURLConnection类,用于实现HTTP客户端功能,以及提供了Servlet API用于实现HTTP服务端的编程。

java程序设计简明教程张晓龙_Java网络编程简明教程相关推荐

  1. Java程序设计——URLDecoder类和URLEncoder类(网络编程)

    普通字符串和MIME字符串之间的转换工具:URLDecoder和URLEncoder工具类 URLDecoder工具类: 方法 功能 decode(String s, String enc) 将MIM ...

  2. java程序设计之网络编程基础教程_Java程序设计之网络编程基础教程

    基本信息 书名:Java程序设计之网络编程基础教程(21世纪高等学校计算机基础实用规划教材) :43.50元 作者:李芝兴 主编 出版社:清华大学出版社 出版日期:2012-12-1 ISBN:978 ...

  3. HTML5+CSS3网站设计教程 (张晓景,胡克) [iso]

    <HTML5+CSS3网站设计教程>系统地讲解了CSS的基础理论和实际运用技术,并结合多个案例讲解了采用CSS与层布局相结合制作网页的方法,在详细讲解各个案例的制作中,不仅介绍了CSS样式 ...

  4. 武汉科技大学计算机学院院长邮箱,武汉科技大学计算机科学与技术学院院长张晓龙来校讲学...

    (通讯员 孙伊珞)11月30日下午14:30,武汉科技大学计算机科学与技术学院院长张晓龙做客我校,在学校综合楼821会议室做了一场主题为<面向新工科,持续强化专业建设和实践教学>的讲座.我 ...

  5. java 对话框计算器,《Java程序设计》第16周礼拜四:GUI编程及文件对话框的使用 计算器...

    <Java程序设计>第16周周四:GUI编程及文件对话框的使用 计算器 项目三:实验六 图形用户界面(教材P279-280) 目标:完成实验六的内容. 运行代码 import java.a ...

  6. 索骥馆-编程语言之《网络编程实用教程(第2版)》扫描版[PDF]

    内容介绍: 本书主要介绍基于tcp/ip协议栈的套接字网络编程技术.全书分为10章,第1章介绍网络编程基础,第2章介绍套接字网络编程接口,第3章介绍windows环境的网络编程,第4章介绍mfc编程, ...

  7. Windows网络编程案例教程-董相志 学习记录 第一个网络程序hostent

    <Windows网络编程案例教程>-董相志 学习记录 第一个网络程序hostent 第一章 网络编程概述 1.3.5第一个网络程序--hostent 对主机的名称和地址解析 WinSock ...

  8. 《Windows网络编程案例教程》-董相志 学习记录 阻塞/非阻塞套接字编程

    <Windows网络编程案例教程>-董相志 学习记录 阻塞/非阻塞套接字编程 2.3 阻塞/非阻塞套接字编程 阻塞套接字编程通信流程图 2.3.1 阻塞套接字客户机编程 1.启动并初始化W ...

  9. java什么是网络接口_java 网络编程 -- IP地址的表示与网络接口信息的获取(InetAddress和NetworkInterface)...

    使用java进行网络程序的开发,可以说是一件令人愉悦的事情,对于用惯了C++网络接口编程的人来说,当他们首次使用Java开发网络应用程序,会发现java开发网络应用是如此的简单,甚至仅用几分钟时间,您 ...

最新文章

  1. 自动化对就业没有影响?看看这张图再说
  2. tcp connection setup的实现
  3. 4.5 matlab三维曲面(mesh、fmesh、meshc、meshz、surf、fsurf、surfc、surfl)
  4. 基于 Kafka + Flink + Redis 的电商大屏实时计算案
  5. 谁都可能是凶手:《八面埋伏》观看手记
  6. HTML极客自适应网址导航模板,更换背景+看板娘
  7. 超神!卡内基博士ImageNet夺冠后转战NLP!
  8. Vmware怎样使用nat和桥接方式解决虚拟机联网问题
  9. iText关于中文的解决方案
  10. 惠普企业警告:Sudo 漏洞可使攻击者获得 Aruba 平台的 root 权限
  11. 【MySQL】MySQL的安装(免费社区版)
  12. CCNA考试题库中英文翻译版及答案8
  13. 质量管理五大工具、七大手法知识点总结
  14. Golang观察者设计模式(十九)
  15. HTML5菜鸟教程在线编译特效,菜鸟教程在线工具
  16. ubuntu16.04下ORB_SLAM2的配置
  17. システム関連の完了コード
  18. 基于STM32的指纹锁
  19. ironpython调用c dll_IronPython.dll,下载,简介,描述,修复,等相关问题一站搞定_DLL之家...
  20. 2020-11-27 PMP 群内练习题 - 光环

热门文章

  1. [中英对照]The sysfs Filesystem | sysfs文件系统
  2. Dive into Python
  3. Android 摇一摇(二)
  4. 在三个层次对Asp.Net的数据操作进行事务
  5. 基于matlab的OFDM百度文库,基于matlab的OFDM仿真总结.doc
  6. python中for用法_python中for的用法探索
  7. oracle表修改语句,Oracle的常用修改表及字段的语句
  8. powerbi python词云图_使用Power BI制作可爱的词云图
  9. C语言 关键字const的作用
  10. 968. 监控二叉树(JavaScript)