什么是网络编程

  网络编程是通过使用套接字来达到进程间通信目的,那什么是套接字呢?其实套接字是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程,具体来看,套接字=IP地址+TCP/UDP + 端口的组合。

网络编程的三要素

  网络编程中,通信“双方”要如何找到彼此呢?互联网是通过IP地址来区分上网电脑的,但是通信的“双方”都是物理电脑上跑的进程,在一台电脑上通过端口来区分不同进程和程序,最后,在互联网通信中,我们分UDP和TCP两种协议。所以网络编程的三要素就是:IP地址,端口号,通信协议。

  IP地址

  IP地址是指互联网协议地址,IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。IP地址编址方案将IP地址空间划分为A、B、C、D、E五类,其中A、B、C是基本类,D、E类作为多播和保留使用。IP地址总共是4个字节,32比特位。

  A类:网络号为1个字节,定义最高比特为0,余下7比特为网络号;

  B类:网络号为2字节,定义最高比特为10,余下14比特为网络号;

  C类:网络号为3字节,定义最高三比特为110,余下21比特为网络号;

  D类:不分网络号和主机号,定义最高四比特为1110,表示一个多播地址,即多目的地传输,可用来识别一组主机;

  E类:以1111开始,为将来使用保留。E类地址保留,仅作实验和开发用;

  另外,全0类地址0.0.0.0表示任意网络。全1的IP地址255.255.255.255是当前子网的广播地址。网络号127。TCP/IP协议规定网络号127不可用于任何网络。其中有一个特别地址:127.0.0.1称之为回送地址(Loopback),它将信息通过自身的接口发送后返回,可用来测试端口状态。

  总之:1~126属A类地址,128~191属B类地址,192~223属C类地址,224~239属D类地址。除了以上四类地址外,还有E类地址,但暂未使用。

  端口号

  端口包括物理端口和逻辑端口。物理端口是用于连接物理设备之间的接口,逻辑端口是逻辑上用于区分服务的端口。TCP/IP协议中的端口就是逻辑端口,通过不同的逻辑端口来区分不同的服务。一个IP地址的端口通过16bit进行编号,最多可以有65536个端口。端口是通过端口号来标记的,端口号只有整数,范围是从0 到65535。

  协议TCP/UDP--指网络传输层的协议

  TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN+ACK,并最终对对方的 SYN 执行 ACK 确认。

  UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP同样也是传输层的协议,但是由于UDP是无连接的协议,所以没有三次握手过程。

Java中网络编程的几个重要类

  Java为网络编程提供了专门的包java.net。下面来看看实现基础网络通信的几个类,也是我们上面总结的几个网络编程要素,除了这些要素外,传输的数据在网络中需要打包等。

InetAddress       此类表示互联网协议 (IP) 地址。
DatagramSocket 此类表示用来发送和接收数据报包的套接字。
ServerSocket 此类实现服务器套接字。
Socket 此类实现客户端套接字(也可以就叫“套接字”)。
DatagramPacket 此类表示数据报包。

UDP网络编程

  用UDP协议进行通信,简单的发送数据按照如下4步走:

  A. 创建发送端Socket对象DatagramSocket
  B. 创建数据,并把数据打包成DatagramPacket
  C. 调用Socket对象的发送方法发送数据包
  D. 释放资源

  接收数据按如下5步走: 

  A:创建接收端Socket对象DatagramSocket
  B:创建一个数据包(接收容器)
  C:调用Socket对象的接收方法接收数据包DatagramPacket
  D:解析数据包,并显示在控制台
  E:释放资源

  下面写一个简单的示例程序,先写服务端的接收数据的程序:

  

public class ReceiveServer {
public static void main(String[] args) throws IOException {
// 创建接收端的Socket对象
DatagramSocket ds = new DatagramSocket(12345); // 创建一个数据包用来接收数据
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length); // 接收数据
ds.receive(dp); // 解析数据
String ipAdd = dp.getAddress().getHostAddress();
String str = new String(dp.getData(), 0, dp.getLength());
System.out.println("地址 " + ipAdd + " 传输的数据为 : " + str); // 释放资源
ds.close();
}
}

客户端的发送程序为:

public class SendClient {
public static void main(String[] args) throws IOException {
// 创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket(); // 创建数据并打包
byte[] bys = "这是UDP传输测试".getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.1.101"), 12345); // 发送数据
ds.send(dp); // 释放资源
ds.close();
}
}

  先启动服务端,再启动客户端,最后服务端输出客户端传来的信息:地址 192.168.1.101 传输的数据为 : 这是UDP传输测试
  如果多次启动客户端,则会报错端口被占用。

  上面的程序虽然实现了基本的通信,但是却有一些问题:

  A: 客户端只能传输一条数据,我们希望可以传输多条或者不想传输后再关闭客户端释放资源。
  B:服务端和客户端只能接受单线程

  为此,将代码改进为键盘录入的多线程版本:

  

public class ChatRoom {
public static void main(String[] args) throws IOException {
DatagramSocket dsSend = new DatagramSocket();
DatagramSocket dsReceive = new DatagramSocket(12346); SendThread st = new SendThread(dsSend);
ReceiveThread rt = new ReceiveThread(dsReceive); Thread t1 = new Thread(st);
Thread t2 = new Thread(rt); t1.start();
t2.start();
}
} class ReceiveThread implements Runnable {
private DatagramSocket ds; public ReceiveThread(DatagramSocket ds) {
this.ds = ds;
} @Override
public void run() {
try {
while (true) {
// 创建一个数据包
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length); // 接收数据
ds.receive(dp); // 解析数据
String ip = dp.getAddress().getHostAddress();
String s = new String(dp.getData(), 0, dp.getLength());
System.out.println("地址: " + ip + " 数据: " + s);
}
} catch (IOException e) {
e.printStackTrace();
}
} } class SendThread implements Runnable { private DatagramSocket ds; public SendThread(DatagramSocket ds) {
this.ds = ds;
} @Override
public void run() {
try {
// 封装键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(
System.in));
String line = null;
while ((line = br.readLine()) != null) {
if ("bye".equals(line)) {
break;
} // 创建数据并打包
byte[] bys = line.getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.1.101"), 12346); // 发送数据
ds.send(dp);
} // 释放资源
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
} }

TCP网络编程

  TCP网络编程是面向连接的,用到的套接字是Socket和ServerSocket,其中Socket是客户端用的套接字,其构造方法如下:

     Socket()
通过系统默认类型的 SocketImpl 创建未连接套接字
Socket(InetAddress address, int port)
创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
Socket(InetAddress host, int port, boolean stream)
已过时。 Use DatagramSocket instead for UDP transport.
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
创建一个套接字并将其连接到指定远程地址上的指定远程端口。
Socket(Proxy proxy)
创建一个未连接的套接字并指定代理类型(如果有),该代理不管其他设置如何都应被使用。
protected Socket(SocketImpl impl)
使用用户指定的 SocketImpl 创建一个未连接 Socket。
Socket(String host, int port)
创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket(String host, int port, boolean stream)
已过时。 使用 DatagramSocket 取代 UDP 传输。
Socket(String host, int port, InetAddress localAddr, int localPort)
创建一个套接字并将其连接到指定远程主机上的指定远程端口。

  常用的方法如下:

 void    close()
关闭此套接字。
void connect(SocketAddress endpoint)
将此套接字连接到服务器。
InetAddress getInetAddress()
返回套接字连接的地址。
InputStream getInputStream()
返回此套接字的输入流。
OutputStream getOutputStream()
返回此套接字的输出流。
int getPort()
返回此套接字连接到的远程端口。
SocketAddress getRemoteSocketAddress()
返回此套接字连接的端点的地址,如果未连接则返回 null。
void shutdownInput()
此套接字的输入流置于“流的末尾”。
void shutdownOutput()
禁用此套接字的输出流。

  ServerSocket套接字是服务器端的套接字,服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。其构造方法如下:

ServerSocket()
创建非绑定服务器套接字。
ServerSocket(int port)
创建绑定到特定端口的服务器套接字。

ServerSocket(int port, int backlog)
利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(int port, int backlog, InetAddress bindAddr)
使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。

  常用方法如下:

 Socket    accept()
侦听并接受到此套接字的连接。
void bind(SocketAddress endpoint)
将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
void bind(SocketAddress endpoint, int backlog)
将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
void close()
关闭此套接字。

  服务器端主要是获取连接上的客户端Socket,然后接可以获取对应的输入输出流进行读取和写入。

  另外,必须先启动服务器,因为TCP是面向连接的,要进行三次握手取得连接后才可以开始写或者读数据。

  下面给出一个客户端上传文件的多线程例子:

public class UploadClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.1.101", 12121); // 封装文本文件
BufferedReader br = new BufferedReader(new FileReader(
"UploadClient.java")); // 封装通道内流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream())); String line = null;
while ((line = br.readLine()) != null) { // 阻塞读
bw.write(line);
bw.newLine();
bw.flush();//刷新
} // Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了
s.shutdownOutput(); // 接收反馈
BufferedReader brClient = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String client = brClient.readLine(); // 阻塞
System.out.println(client); // 释放资源
br.close();
s.close();
}
} public class UploadServer {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(12121); while (true) {
Socket s = ss.accept();//每接受一个Socket则新建一个对应的线程处理
new Thread(new UserThread(s)).start();
}
}
} public class UserThread implements Runnable {
//Socket对象
private Socket s; public UserThread(Socket s) {
this.s = s;
} @Override
public void run() {
BufferedReader br = null;
BufferedWriter bw = null;
try {
// 封装通道内的流
br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 封装文本文件,为了防止名称冲突加上当前时间
String newName = System.currentTimeMillis() + ".txt";
bw = new BufferedWriter(new FileWriter(newName)); String line = null;
while ((line = br.readLine()) != null) { // 阻塞读
bw.write(line);
bw.newLine();
bw.flush();//刷新
} // 给出反馈,客户端可以终止
BufferedWriter bwServer = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush(); } catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(s!=null){
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} }

  

【Java基础】Java网络编程基础知识的更多相关文章

  1. 大数据学习笔记——Java篇之网络编程基础

    Java网络编程学习笔记 1. 网络编程基础知识 1.1 网络分层图 网络分层分为两种模型:OSI模型以及TCP/IP网络模型,前者模型分为7层,是一个理论的,参考的模型:后者为实际应用的模型,具体对 ...

  2. Java SE之网络编程:知识框架

  3. java第九节 网络编程的基础知识

    /** * * 网络编程的基础知识 * 网络协议与TCP/IP * IP地址和Port(端口号) * 本地回路的IP地址:127.0.0.1 * 端口号的范围为0-65535之间,0-1023之间的端 ...

  4. Java网络编程基础(Netty预备知识)

    今天在家休息,闲来无事,写篇博客,陶冶下情操~~~ =================我是分割线================ 最近在重新学习Java网络编程基础,以便后续进行Netty的学习. 整 ...

  5. Java网络编程和NIO详解开篇:Java网络编程基础

    Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...

  6. 黑马程序员:Java基础总结----网络编程

    黑马程序员:Java基础总结 网络编程   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 网络编程 网络通讯要素 . IP地址 . 网络中设备的标识 . 不易记忆,可用 ...

  7. java网络编程基础——网络基础

    java网络编程 网络编程基础 1.常用的网络拓扑结构: 星型网络.总线网络.环线网络.树形网络.星型环线网络 2.通信协议的组成 通信协议通常由3部分组成: 语义部分:用于决定通信双方对话类型 语法 ...

  8. java网络编程基础

    前言 通过网络进行数据传输时,一般使用TCP/UDP进行数据传输.但是两个的区别就是TCP可靠,UDP不可靠.两个的共同之处就是都需要建立socket套接字,将IP地址和端口port进行绑定.但是服务 ...

  9. [Java入门笔记] 面向对象编程基础(二):方法详解

    什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...

  10. C#网络编程基础知识

    C#网络编程基础知识一 1.IPAddress类 用于表示一个IP地址.IPAddress默认构造函数 public IPAddress(long address);一般不用 其中Parse()方法最 ...

随机推荐

  1. _CrtIsValidPointer 问题

    从微软站点: 检查指针有效性下面的示例使用 _CrtIsValidPointer 验证给定的内存范围对于读或写是否有效. _ASSERTE(_CrtIsValidPointer( address, s ...

  2. 2026-Keroro侵略地球

    描述 Keroro来侵略地球之前,曾跟Giroro伍长打赌:“我一个人灭掉整个地球给你看!”. 于是Keroro同学真的自己一个人来到地球开始他的侵略行动了.从K隆星出发之前,Keroro从Kurur ...

  3. ****JFinal 部署在 Tomcat 下推荐方法

    首先明确一下 JFinal 项目是标准的 java web 项目,其部署方式与普通 java web 项目没有任何差别.Java Web 项目在 Tomcat 下部署有一些不必要的坑需要避免 经常有人 ...

  4. hdu 4035 Maze 概率DP

        题意:    有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树,    从结点1出发,开始走,在每个结点i都有3种可能:        1.被杀死,回到结点1处(概率为ki)      ...

  5. PowerDesigner将name自动添加到Comment注释的方法 VB代码

    Option Explicit ValidationMode = True InteractiveMode = im_Batch Dim mdl ' the current model ' get t ...

  6. POJ2635——The Embarrassed Cryptographer(高精度取模+筛选取素数)

    The Embarrassed Cryptographer DescriptionThe young and very promising cryptographer Odd Even has imp ...

  7. DSPLIB for C6455+CCSv3.3

    问题描述: Hello everybody, I was looking for DSPLIB libraries optimized for C6455 processors. I found th ...

  8. MQ-传输方式Topic和Queue的对比

    Jms规范里的两种message传输方式Topic和Queue,两者的对比如下表():   Topic Queue 概要 Publish  Subscribe messaging 发布订阅消息 Poi ...

  9. 第三部分 overlay 学习

    前文仅了解了overlay HAL的架构,下面继续看看系统层是如何调用Overlay模块. 1.测试代码 frameworks/base/libs/surfaceflinger/tests/overl ...

  10. poj 3083 Children of the Candy Corn(DFS+BFS)

    做了1天,总是各种错误,很无语 最后还是参考大神的方法 题目:http://poj.org/problem?id=3083 题意:从s到e找分别按照左侧优先和右侧优先的最短路径,和实际的最短路径 DF ...