Day19 网络编程

时间:2024-01-08 08:13:38

基本概念

网络:一组由网线连接起来的计算机。

网络的作用

  1.信息共享。

  2.信息传输。

  3.分布式处理。

  4.综合性的处理。

internet:互联网

Internet:是互联网中最大的一个。

www:万维网,web,是Internet因特网的一个服务。

协议

  IP:网际传输协议。传输数据,不保证数据的准确性。

  TCP:传输控制协议,可以确保数据的准确性。

  HTTP(超文本传输协议):超文本

  FTP(文件传输协议):文件传输协议

  SMTP(简单邮件传输协议):邮件的传输。

IP地址:网络上通信实体的标识。

Day19 网络编程

IP地址分类

A:0.0.0.0 - 127.255.255.255,其中0和127不可用

B:128.0.0.0 - 191.255.255.255

C:192.0.0.0 - 223.255.255.255

D:224.0.0.0 - 239.255.255.255

E:240.0.0.0 - 255.255.255.255,其中段255不可用

服务端口:计算机通过不同的服务端口来区分不同网络服务,就像通过进程号区分不同的进程一样;常见服务的端口,HTTP(80),FTP(21)

OSI与TCP/IP体系模型

Day19 网络编程

Day19 网络编程

网络体系结构解决异质性问题采用的是分层的方法——把复杂的网络互联问题划分为若干个较小的、单一的问题,在不同层上予以解决。

OSI(Open System Interconnection)参考模型将网络的不同功能划分为7层:

  应用层:处理网络应用

  表示层:数据表示

  会话层:主机间通信

  传输层:端到端的连接

  网络层:寻址和最短路径

  数据链路层:介质访问(接入)

  物理层:二进制传输

Day19 网络编程

通信实体的对等层之间不允许直接通信,各层之间是严格的单向依赖,上层(Service user)使用下层提供的服务,下层(Service provider)向上层提供服务。

对等层通信的实质对等层实体之间虚拟通信,下层向上层提供服务,实际通信在最底层完成。

OSI各层所使用的协议

应用层:Telnet、FTP、HTTP、DNS、SMTP、POP3

传输层:TCP、UDP

  TCP:面向连接的可靠的传输协议。

  UDP:是无连接的,不可靠的传输协议。

网络层:IP、ICMP、IGMP

TCP

  TCP是Transfer Control Protocol(传输控制协议)的简称,是一种面向连接的保证可靠传输的协议

  在TCP/IP协议中,

  IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一确定Internet上的一台主机

  而TCP层则提供面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。

  通过TCP协议传输,得到的是一个顺序的无差错的数据流。

  发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信。

  当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。

  TCP是一个基于连接的协议,它能够提供两台计算机之间的可靠的数据流。

  HTTP、FTP、Telnet等应用都需要这种可靠的通信通道。

UDP

  UDP是User Datagram Protocol的简称,是一种无连接的协议

  UDP是从一台计算机向另一台计算机发送称为数据报的独立数据包的协议,该协议并不保证数据报是否能正确地到达目的地,它是一个非面向连接的协议。

  每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达时间以及内容的正确性都是不能保证的。

TCP和UDP的比较

  使用UDP时,每个数据报中都给出了完整的地址信息,因此无需建立发送方和接收方的连接。

  对于TCP协议,由于它是一个面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中多了一个连接建立的时间。

  使用UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。

  TCP没有这方面的限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大量的数据。

  UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。

  TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。

  可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽。因此TCP传输的效率不如UDP高。

  TCP在网路通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。

  相比之下UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。

TCP/IP与OSI参考模型的对应关系

Day19 网络编程

URL

统一资源定位符。

格式

protocol://hostname[:port]/path/[?query]#fragment
协议 ://主机名或IP:端口/路径?字符串=值&字符串=值#片段

常用方法

getProtocol():获得协议名称

getHost():获得主机名称或IP

getPort():获得端口

getDefaultPort():获得默认端口

getQuery():获得查询串

getRef():获得片段

getPath():获得路径

getFile():获得路径和查询串

public class TestURL {

    public static void main(String[] args) throws MalformedURLException {
// URL
URL url = new URL("http://127.0.0.1:8080/data/a.txt?id=1&page=2#hello");
System.out.println(url.getProtocol());//协议
System.out.println(url.getHost());//主机
System.out.println(url.getPort());//端口
System.out.println(url.getDefaultPort());//默认端口
System.out.println(url.getPath());//路径
System.out.println(url.getFile());//路径 和 查询串
System.out.println(url.getQuery());//查询串
System.out.println(url.getRef());//片段
} }

URL资源下载

openStream()

public class TestURL1 {

    public static void main(String[] args) throws IOException {
// URL-openStram()资源下载
URL url = new URL("http://img15.3lian.com/2016/h1/233/d/156.jpg");
//获得了 URL的定位资源得 输入流
InputStream in = url.openStream();
OutputStream out = new FileOutputStream("d:/data/datou.jpg");
int temp;
while((temp = in.read())!= -) {
out.write(temp);
}
in.close();
out.close();
} }

InetAddress类

常用方法

getLocalHost():获得本机地址

getByName(String host):通过主机名或IP地址获得一个InetAddress的一个封装

getHostName():获得主机名称

getHostAddress():获得主机地址

public class TestInetAddress {

    public static void main(String[] args) throws UnknownHostException {
// InetAddress
//获得 本机的IP
System.out.println(InetAddress.getLocalHost());
//通过 主机名 后 IP地址 获得一个 InetAddress的一个封装
InetAddress i = InetAddress.getByName("www.baidu.com");
//单独 获得 主机的 IP地址
System.out.println(i.getHostAddress());
//主机的名称
System.out.println(i.getHostName());
} }

Socket

Socket通讯

网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。

在传统的UNIX环境下可以操作TCP/IP协议的接口不止Socket一个,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

使用Socket进行网络通信的过程

服务器程序将一个套接字绑定到一个特定的端口,并通过此套接字等待和监听客户的连接请求。

客户程序根据服务器程序所在的主机名和端口号发出连接请求。

Day19 网络编程

如果一切正常,服务器接受连接请求。并获得一个新的绑定到不同端口地址的套接字。(不可能有两个程序同时占用一个端口)。

客户和服务器通过读写套接字进行通讯。

Day19 网络编程

使用ServerSocketSocket实现服务器端和客户端的Socket通信。

Day19 网络编程

其中:

  左边ServerSocket类的构造方法可以传入一个端口值来构建对象。

  accept()方法监听向这个socket的连接并接收连接。它将会阻塞直到连接被建立好。连接建立好后它会返回一个Socket对象。

  连接建立好后,服务器端和客户端的输入流和输出流就互为彼此,即一端的输出流是另一端的输入流。

对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:
(1) 创建Socket;
(2) 打开连接到Socket的输入/出流;
(3) 按照一定的协议对Socket进行读/写操作;
(4) 关闭Socket.

Socket通信程序测试

server端

 package day19.socket1;

 import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner; //服务器 1.0
public class Server { public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(); //等待客户端连接,连接成功分配一个 Socket
Socket socket = server.accept();
//
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
//
Scanner in = new Scanner(is);
PrintWriter out = new PrintWriter(os,true);//刷新
//写
out.println("客户端你连接成功了!");
out.println("end");//
//读
String sr;
while(true) {
sr = in.nextLine();
System.out.println("客户端说了:"+sr);
if(sr.equals("end")) {
break;
}
}
//关
socket.close();//客户端
} }

client端

 package day19.socket1;

 import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner; //客户端
public class Client { public static void main(String[] args) throws UnknownHostException, IOException {
// 要访问的服务器 的IP地址,和端口
Socket socket = new Socket(InetAddress.getLocalHost(), );
//获得 Socket流
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
//包装
Scanner in = new Scanner(is);
// true 自动刷新缓冲区
PrintWriter out = new PrintWriter(os,true);
//读
String sr,sw;
while(true) {
sr = in.nextLine();//读服务器传过来的一行信息
System.out.println("服务器说了:"+sr);
if(sr.equals("end")) {
break;
}
}
//写
Scanner input = new Scanner(System.in);
while(true) {
System.out.print("客户端输入信息:");
sw = input.next();
//写
out.println(sw);
if(sw.equals("end")) {
break;
}
}
//关
socket.close(); } }

然后先运行服务器端,再运行客户端,可以看到,运行客户端之后输出服务器端的后续代码。

表明连接建立后才会往下执行。

使用多线程实现简单聊天

server端

 package day19.socket5;

 import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner; /**
* 服务器
* @version 5.0
*/
public class TestServer {
public static void main(String[] args) throws IOException {
@SuppressWarnings("resource")
ServerSocket server = new ServerSocket();
//分配客户端
Socket socket = server.accept();
//流
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
//包装
Scanner in = new Scanner(is);
PrintWriter pw = new PrintWriter(os, true);
System.out.println("----------------服务器----------------------");
//写
pw.println("--客户端连接服务器成功--");
SSWrite w = new SSWrite(pw,socket);
Thread tssw = new Thread(w,"服务器-写-线程");
tssw.start();
//读
SSRead r = new SSRead(in);
Thread tssr = new Thread(r,"服务器-读-线程");
tssr.start();
}
}
//读线程
class SSRead implements Runnable{
Scanner in;
public SSRead(Scanner in) {
this.in = in;
}
@Override
public void run() {
String sr;
while (in.hasNext()) {
sr = in.nextLine();
System.out.println("来自客户端的消息:"+sr);
if (sr.equals("end")) {
break;
}
}
}
}
//写线程
class SSWrite implements Runnable{
PrintWriter pw;
Socket socket;
public SSWrite(PrintWriter pw,Socket socket) {
this.pw = pw;
this.socket = socket;
}
@Override
public void run() {
String sw;
Scanner input = new Scanner(System.in);
while (input.hasNextLine()) {
sw = input.nextLine();
pw.println(sw);
if (sw.equals("end")) {
try {
socket.close();//关闭
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
}

client端

 package day19.socket5;

 import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* 客户端
* @version 5.0
*/
public class Client { public static void main(String[] args) throws UnknownHostException, IOException { // 服务器IP地址,端口号
Socket socket = new Socket(InetAddress.getLocalHost(), ); //和服务器聊天
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
//包装
Scanner in = new Scanner(is);
PrintWriter pw = new PrintWriter(os);
System.out.println("----------------客户端-----------------------");
//读写操作
//读
Read r = new Read(in);
Thread tr = new Thread(r,"读-线程");
tr.start();
//写
Write w = new Write(pw,socket);
Thread tw = new Thread(w,"写-线程");
tw.start();
//关闭流
// s.close();
}
}
//读线程
class Read implements Runnable{
Scanner in;
public Read(Scanner in) {
this.in = in;
}
@Override
public void run() {
String sr;
while (in.hasNext()) {
sr = in.nextLine();
System.out.println("来自服务器的消息:"+sr);
if (sr.equals("end")) {
break;
}
}
in.close();
}
}
//写线程
class Write implements Runnable{
PrintWriter pw;
Socket socket;
public Write(PrintWriter pw,Socket socket) {
this.pw = pw;
this.socket = socket;//关闭客户端
}
@Override
public void run() {
String sw;
Scanner input = new Scanner(System.in);
while (input.hasNextLine()) {
sw = input.nextLine();
pw.println(sw);
pw.flush();
if (sw.equals("end")) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}//
break;
}
}
}
}

UDP简单使用

server端

 package day19.udp1;

 import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException; public class UServer { public static void main(String[] args) throws IOException {
// 接收方 9999
byte [] b = new byte[];
//打包
DatagramPacket dp = new DatagramPacket(b, b.length);
//接收方
DatagramSocket ds = new DatagramSocket();
//接收
ds.receive(dp);
byte [] bt = dp.getData();
System.out.println(new String(bt,"gbk"));
ds.close();
} }

client端

 package day19.udp1;

 import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner; public class UClient { public static void main(String[] args) throws IOException {
// 发送方
Scanner input = new Scanner(System.in);
System.out.println("输入要传输的数据:");
String s = input.next();
//
byte [] b = s.getBytes();
//打包 接收方的端口
DatagramPacket dp = new DatagramPacket(b,b.length,InetAddress.getLocalHost(),);
//发送 发送方的端口
DatagramSocket ds = new DatagramSocket();
ds.send(dp);
//
ds.close();
} }