网络编程概述:
计算机网络:
是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议
的管理和协调下,实现资源共享和信息传递的计算机系统。
计算机网络的主要功能:
1:资源共享
2:信息传输与集中处理
3:均衡负荷与分布处理
4:综合信息服务
计算机网络的分类:
局域网(LAN)、城域网(MAN)、广域网(WAN)。Internet可视为世界最大的广域网
网络模型:
OSI参考模型:
计算机网络之间以何种规则进行通信,就是网络模型研究问题。国际标准化组织ISO与1978年提出"开放系统互连参考模型",
即OSI(OpenSystem Interconnection)。OSI参考模型把计算机网络分成物理层、数据链路层、网络层、传输层、会话层、
表示层、应用层。OSI参考模型已成为各种计算机网络结构的参考标准。
TCP/IP协议模型:
按TCP/IP协议模型,网络被分成物理+数据链路、网络层、传输层、应用层。TCP/IP协议模型和OSI参考模型有着大致的对应关系。
--------------------------
应用层
--------
表示层 应用层(HTTP POP3 SMTP FTP TELNET)
--------
会话层
--------------------------
传输层 传输层 (TCP UDP)
--------------------------
网络层 网络层 (IP)
--------------------------
数据链路层
-------- 物理+数据链路
物理层
----------------------------
OSI分层模型和TCP/IP分层模型的对应关系
网络通信的三要素:
1:IP地址:
IP地址用于唯一的标识网络中的一个通信实体,
IP地址的分类:
IP地址的分类:
A类:1.0.0.1---127.255.255.254
(1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)
(2)127.X.X.X是保留地址,用做循环测试用的。
B类:128.0.0.1---191.255.255.254
172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
C类:192.0.0.1---223.255.255.254
192.168.X.X是私有地址
D类:224.0.0.1---239.255.255.254
E类:240.0.0.1---247.255.255.254
如何在查看本机的ip地址:打开命令行,输入ipconfig
测试网络连接是否良好:打开命令行,输入ping ip地址
本地回环地址:127.0.0.1
网络地址:xxx.xxx.xxx.0
广播地址:xxx.xxx.xxx.255
案例体现:
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* java提供了InetAddress类来代表IP地址,InetAddress类没用提供构造器,而是通过静态的构造方法来获取InetAddress实例。
* 1:static InetAddressgetByName(String host):在给定主机名或者ip地址的情况下,获取InetAddress的实例
* 2:staticInetAddress getLocalHost() 返回本地主机所对应的InetAddress实例
* 3:staticInetAddress[] getAllByName(String host) 在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址
*InetAddress还提供了获取InetAddress实例对应的IP地址和主机名的方法:
* 1: StringgetHostAddress() 返回 IP 地址字符串(以文本表现形式)。
* 2: StringgetHostName() 获取此IP 地址的主机名。
* 3:StringgetCanonicalHostName() 获取此IP 地址的完全限定域名。
* 4: booleanisReachable(int timeout) 测试是否可以达到该地址。
* */
public class InetAddressTest {
public static void main(String[] args) throws IOException {
//获取本机的InetAddress实例
InetAddress ia1 = InetAddress.getLocalHost();
//获取本机的IP地址
System.out.println("我的IP地址是:"+ ia1.getHostAddress());
//获取本机的主机名
System.out.println("我的主机名是:" + ia1.getHostName());
//通过主机名创建对象
InetAddress ia2 = InetAddress.getByName("113.251.70.43");
System.out.println("该计算机的主机名是:" + ia2.getHostName());
System.out.println("该计算机的ip地址是:" + ia2.getHostAddress());
}
}
2:端口号:
在明确IP地址的情况下,用于表示数据具体交给哪个通信程序处理。
因此,端口号就是应用程序与外界交流的出入口。
端口号的分类:
1:公认端口:从0到1023,它们紧密绑定一些特定的服务
2:注册端口:从1024到49151,应用程序一般使用这个范围内的端口
3:动态或私有端口:从49152到65535,这些端口是应用程序使用的动态端口。
常见的端口:
web服务:80
web服务器:默认是8080
数据库:3306
3:传输协议:
常用的TCP协议和UDP协议
UDP协议:是一种面向非连接的协议,不需要建立连接。将数据源和目的封装成数据包中,
每个数据报的大小限制在64k;因无连接,所以是不可靠协议;速度快
作用:完成网络数据流和数据报之间的转换。在信息的发送端,UDP协议将网络数据流
封装成数据报,然后将数据发送出去;在信息的接收端,UDP协议将数据报转换成
实际的数据内容。
应用场景:聊天、视频会话、桌面共享等。
TCP协议:建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手
完成连接,是可靠协议;效率会稍低
UDP协议和TCP协议直接位于IP协议之上。IP协议属于网络层协议,UDP协议和TCP协议都属于传输层协议
Socket:
Socket就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket之间的通信,数据在两个Socket之间
通过IO流传输
基于UDP协议的网络编程:
使用DatagramSocket发送、接收数据:
Java使用DatagramSocket代表UDP协议的Socket,DatagramSocket本身只是码头,不维护状态,不能产生IO流
它的唯一作用就是接收和发送数据报,Java使用DatagramPacket来代表数据报,DatagramSocket接收和发送
数据都是通过DatagramPacket对象来完成的
DatagramSocket的构造器:
DatagramSocket(int port) 创建数据报套接字并将其绑定到本地主机上的指定端口。接收端和发送端均可使用
DatagramSocket() 构造数据报套接字并将其绑定到本地主机上任何可用的端口。仅用于发送端
DatagramSocket(int port, InetAddress laddr) 创建数据报套接字,将其绑定到指定的本地地址,指定端口
DatagramSocket的方法:
voidreceive(DatagramPacket p) 接收数据报,该方法会阻塞调用该方法的线程,直到接收到数据为止
voidsend(DatagramPacket p) 发送数据报
DatagramPacket的构造器:
DatagramPacket(byte[] buf, int length) 先创建一个空数组,用来接收长度为 length 的数据包。接收存储数据
DatagramPacket(byte[] buf, int length, InetAddress address, intport)
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
DatagramPacket的方法:
byte[]getData() 返回数据缓冲区。
InetAddressgetAddress() 返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
intgetPort() 返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
intgetLength() 返回将要发送或接收到的数据的长度。
案例体现一:
/*
* Description:
* 发送端从键盘录入数据,在接收端显示,模拟一个简单的聊天小程序
*/
package com.itheima.sent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class SentDemo2 {
public static void main(String[] args) throws IOException {
//1.创建UDPSocket服务对象
DatagramSocket ds = new DatagramSocket(8888);
//2.确定数据,将数据打包
BufferedReader br = new BufferedReader(newInputStreamReader(System.in));
String line = null;
while((line = br.readLine()) != null)
{
//自定义结束标记
if("886".equals(line))
{
break;
}
DatagramPacket dp = new DatagramPacket(line.getBytes(),line.length(), InetAddress.getByName("192.168.1.101"), 10000);
//3.发送数据
ds.send(dp);
}
//4.关闭资源
ds.close();
}
}
package com.itheima.receive;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveDemo1 {
public static void main(String[] args) throws Exception {
//步骤:
//1.创建UDP的Socket服务
DatagramSocket ds = new DatagramSocket(10000);
while(true){
//2.定义一个空的数据报,因为要接收存储数据,
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
//3.通过UDP服务的receive()方法,将数据存入数据包中
ds.receive(dp);
//4.通过数据报的方法,解析数据
String data = new String(dp.getData(), 0, dp.getLength());
System.out.println("ip:" +dp.getAddress().getHostAddress() + "端口号:" + dp.getPort() + " :" + data);
//5.关闭资源
}
}
}
案例体现二:
/*
对上面程序进行改进,加入多线程
*/
import java.io.IOException;
import java.net.DatagramSocket;
import com.itheima.receive.ReceiveThread;
import com.itheima.sent.SentThread;
public class ChatRoom {
public static void main(String[] args) throws IOException {
DatagramSocket ds1 = new DatagramSocket();
DatagramSocket ds2 = new DatagramSocket(12306);
SentThread st = new SentThread(ds1);
ReceiveThread rt = new ReceiveThread(ds2);
st.start();
rt.start();
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class SentThread extends Thread{
private DatagramSocket ds;
public SentThread(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = br.readLine()) != null)
{
DatagramPacket dp = new DatagramPacket(line.getBytes(),line.length(), InetAddress.getByName("192.168.1.101"), 12306);
ds.send(dp);
if("886".equals(line))
break;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally
{
try {
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ds.close();
}
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveThread extends Thread{
private DatagramSocket ds;
public ReceiveThread(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try {
while(true){
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
ds.receive(dp);
String data = new String(dp.getData(), 0, dp.getLength());
System.out.println("ip:" +dp.getAddress().getHostAddress() + "*****" + data);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
基于TCP协议的网络编程:
使用SeverSocket创建TCP服务器端:
Java中能够接收其他通信实体连接请求的类是ServerSocket,SeverSocket对象用于监听来自客户端的Socket连接,
如果没有连接,它将一直处于等待状态。
SeverSocket的构造方法:
ServerSocket(int port) 创建绑定到特定端口的服务器套接字。
SeverSocket的方法:
Socketaccept() :如果接收到一个客户端Socket的连接请求,
该方法将返回一个与客户端Socket对应的Socket对象。否则该方法将一直处于等待状态,线程被阻塞。
使用Socket客户端进行通信:
客户端可以使用Socket的构造器来连接到指定的服务器。
Socket的构造方法:
Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
如果没有指定,系统默认使用本地主机的IP地址,默认分配端口
Socket的方法:
InputStream getInputStream() 返回该Socket对象对应的输入流,让程序通过该输入流向Socket读取数据
OutputStream getOutputStream() 返回该Socket对象对应的输出流,让程序通过该流向Socket中写入数据
voidshutdownOutput() 禁用此套接字的输出流。告诉服务端数据已写完
案例体现一:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/*
*TCP客户端:
* 通过查阅API文档发现,在Socket对象建立时,就指定连接的主机,
* 因为TCP是面向连接的,所以在建立Socket服务时,就要有服务端的存在,
* 并且连接成功后,才能进行数据传输
*1:建立客户端的Socket服务,并明确要连接的服务器。
*2:如果连接建立成功,就表明,已经建立了数据传输的通道.
* 就可以在该通道通过IO进行数据的读取和写入.
* 该通道称为Socket流,Socket流中既有读取流,也有写入流.
*3:通过Socket对象的方法,可以获取这两个流
*4:通过流的对象可以对数据进行传输
*5:如果传输数据完毕,关闭资源
*/
public class ClientDemo1 {
public static void main(String[] args) throws IOException {
//1:建立客户端的Socket服务,并明确要连接的服务器。
Socket s = new Socket("192.168.1.101", 10001);
//2:向管道写入
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
pw.println("haha,我来了");
BufferedReader br = new BufferedReader(newInputStreamReader(s.getInputStream()));
String line = br.readLine();
System.out.println(line);
//关闭资源
s.close();
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/*
TCP服务端:
1:建立服务器端的socket服务,需要一个端口
2:服务端没有直接流的操作,而是通过accept方法获取客户端对象,在通过获取到的客户端对象的流和客户端进行通信
3:通过客户端的获取流对象的方法,读取数据或者写入数据
4:如果服务完成,需要关闭客户端,然后关闭服务器,但是,一般会关闭客户端,不会关闭服务器,因为服务端是一直提供服务的
*/
public class ServerDemo1 {
public static void main(String[] args) throws IOException {
// 建立服务器的Socket对象,指定监听端口
ServerSocket ss = new ServerSocket(10001);
// 返回当前连接的客户端对象
Socket s = ss.accept();
// 获取输入流对象
BufferedReader br = new BufferedReader(newInputStreamReader(s.getInputStream()));
String line = br.readLine();
System.out.println("ip:" +s.getInetAddress().getHostAddress() + " :" + line);
//获取输出流对象,给客户端反馈
PrintWriter pw = new PrintWriter(s.getOutputStream());
pw.println("哈哈,我走了");
//关闭资源
s.close();
ss.close();
}
}
案例体现二:
/*
* 功能:向服务器并发上传图片
* 为了让多个客户端同时访问服务端,那么最好就把每一个客户端封装到一个单独的线程
* 就可以同时处理多个客户端的请求
* 如何定义线程呢?
* 只要明确每一个客户端要在服务端执行的代码即可
* */
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/*
* 功能:向服务器上传图片
* 1:服务端点
* 2:从客户端读取图片
* 3:通过Socket输出流发送给服务端
* 4:从服务端获取反馈信息
* 5:关闭资源
* */
public class ClientDemo3 {
public static void main(String[] args) throws IOException {
//创建Socket对象
Socket s = new Socket("192.168.1.101", 10011);
//封装数据源
BufferedInputStream bis = new BufferedInputStream(newFileInputStream("K:\\pic.jpg"));
//封装目的地
BufferedOutputStream pw = newBufferedOutputStream(s.getOutputStream());
byte[] bys = new byte[1024];
int len = 0;
while((len = bis.read(bys)) != -1)
{
pw.write(bys, 0, len);
pw.flush();
}
//告诉服务端数据已写完
s.shutdownOutput();
BufferedReader br = new BufferedReader(newInputStreamReader(s.getInputStream()));
String line = br.readLine();
System.out.println(line);
bis.close();
s.close();
}
}
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
public class PicServerThread implements Runnable{
private Socket s;
public PicServerThread(Socket s)
{
this.s = s;
}
@Override
public void run() {
String ip = s.getInetAddress().getHostAddress();
try {
int count = 1;
System.out.println(ip + " 进来啦");
File file = new File("k:\\" + "pic" + count +".jpg");
while(file.exists()){
file = new File("k:\\" + "pic" + (count++) +".jpg");
}
BufferedInputStream br = newBufferedInputStream(s.getInputStream());
BufferedOutputStream pw = new BufferedOutputStream(newFileOutputStream(file));
byte[] bys = new byte[1024];
int len = 0;
while((len = br.read(bys)) != -1)
{
pw.write(bys, 0, len);
pw.flush();
}
PrintWriter pw1 = new PrintWriter(s.getOutputStream());
pw1.println("上传成功");
pw1.flush();
pw.close();
s.close();
} catch (IOException e) {
throw new RuntimeException(ip + "上传失败");
}
}
}
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SeverDemo4 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10011);
while(true)
{
Socket s = ss.accept();
new Thread(new PicServerThread(s)).start();
}
}
}