1. 设络通讯要素
1.1 ip地址,端口号,传输协议
1、找到对方
方式:ip地址
分四段,最大255
本地回环地址 127.0.0.1 主机名:localhost
有些被保护的地址 192.168.0.1
子网掩码:公网不够用,所以进行了分段。
2、 端口号
将数据发送到指定的程序上
为了标示这些应用程序,所以给这个网络应用程序都用数字进行标示
为了方便称呼这个数字,叫做端口,这个是个逻辑端口。
一般 0-65535。 0`1024通常是系统使用或者保留。
所谓防火墙,其功能就是将发送到某程序端口的数据屏蔽掉以及将从该程序端口发出的数据也屏蔽掉。
3、定义通信规则
这个规则称之为协议
通用协议:TCP/IP 既可以用于局域网也可以用于广域网
通信方式:tcp udp
4、为了安全起见:某些特殊单位具有特有的通讯协议
网络模型
OSI参考模型:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
TPC/IP 模型:应用层、 传输层、网际层、主机至网络层
web 应用层
底层 传输和网际层
传输层通常tcp和udp协议
网际层:ip协议
应用层:http ftp协议
1.2 七层模型
1、物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换(数字信号与模拟信号))。这一层的数据是比特流。
2、数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。
3、网络层:主要将下层接收到的数据进行IP地址(例,192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。
4、传输层:定义了一些传输数据的协议和端口号(WWW端口号80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层叫做段。
5、会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接收会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。
6、表示层:主要是进行对接收的数据进行解释,加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够识别的东西(如图片、声音等)。
7、应用层:主要是一些终端的应用,比如说FTP(各种文件下载)、WEB(IE浏览)、QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西,就是终端应用)。
2. UDP和TCP
2.1 udp传输(无连接、大小64k、不可靠、速度快)
将数据、源、目的封装成数据包中,不需要建立连接
每个数据包的大小限制在64k内
因面向无连接,是不可靠协议
不需要建立连接,速度快但容易丢包。
很多聊天工具都是udp协议,数据不重要。
对讲机类似udp(对方不一定在)。
2.2 tcp传输(需连接、大小无限制、可靠、速度慢、三次握手)
建立连接,形成传输数据的通道。
在连接中进行大数据量传输。
通过三次握手完成连接,是可靠协议。
必须建立连接,效率会降低。
就像打电话。
三次握手:
——你在么
——我在
——(告诉你)知道你在了
3. 域名解析
在浏览器中输入新浪的域名,DNS解析域名成IP,然后计算机再通过获取到的IP访问新浪服务器。
域名解析,最先走是本地的hosts(C:\WINDOWS\system32\drivers\etc\hosts)文件,解析失败了,才去访问DNS服务器解析、获取IP地址。
通过hosts文件可以屏蔽游戏网站内容弹出,例如:在hosts文件中添加,127.0.0.1 www.1234.com。
4. Socket
就是为网络服务提供的一种机制
通信的两端都有Socket
网络通信其实就是Socket之间的通信
数据在两个Socket间通过IO传输
5. UDP示例
DatagramSocket(用来发送和接收数据报包的套接字)与DatagramPacket(数据报包)。
建立发送端,接收端。
建立数据包。
调用Socket的发送接收方法。
关闭Socket。
import java.net.*;
public class H_06UDPSent {
public static void main(String[] args) throws Exception {
//创建udp服务,通过DatagramSocket对象
DatagramSocket ds=new DatagramSocket();
//确定数据,并封装成数据包
byte[] data="jintian tianqi cucuo ".getBytes();
//字符串数据封装成字节数组
//DatagramPacket(byte[] buf, int length, InetAddress address, int port)
DatagramPacket dp=newDatagramPacket(data,data.length,InetAddress.getLocalHost(),10000);
//通过socket服务,将已有的数据包发送出去,通过sent方法
ds.send(dp);
//关闭资源
ds.close();//面向无连接,数据丢失
}
}
6. UDP示例2
import java.io.*;
import java.io.InputStreamReader;
import java.net.*;
public class H_09UDPSend
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds=new DatagramSocket();
while(true)
{
BufferedReader bufr=new BufferedReader(newInputStreamReader(System.in)); //读取键盘录入
String s=bufr.readLine();
byte[] buf=s.getBytes();//转换为字节数组
DatagramPacket dp=newDatagramPacket(buf,buf.length,InetAddress.getLocalHost(),9000);//指定9000端口
ds.send(dp);//发送数据
//ds.close();
}
}
}
//接收端
public class H_09UDPRece {
public static void main(String[] args) throws Exception {
DatagramSocket ds=new DatagramSocket(9000);//监听9000端口
while(true)
{
byte[] buf=new byte[1024];//最大也就1024*64
DatagramPacket dp=new DatagramPacket(buf,buf.length);
ds.receive(dp);//接收数据
sop(new String(dp.getData(),0,dp.getLength())+"--");
//sop(dp.getAddress().getHostAddress());
//sop(dp.getPort());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
7. TCP演示
7.1 客户端(Client)首先与服务端(Server)建立连接,形成通道(其实就是IO流),然后,数据就可以在通道之间进行传输,并且单个Server端可以同时与多个Client端建立连接。
Socket和ServerSocket,建立客户端和服务器端.
建立连接后,通过Socket中的IO流进行数据的传输。
关闭socket。
同样,客户端与服务器端是两个独立的应用程序。
7.2 TCP客户端
客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。
连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过getInputStream(),getOutputStream()获取即可。
与服务端通讯结束后,关闭Socket。
7.3 TCP服务端
服务端需要明确它要处理的数据是从哪个端口进入的。
当有客户端访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。
当该客户端访问结束,关闭该客户端。
import java.io.*;
import java.net.*;
import java.io.*;
import java.net.*;
public class H_12TcpDemo {
public static void main(String[] args) throws Exception {
Socket s=new Socket(InetAddress.getLocalHost(),10005);
OutputStream out=s.getOutputStream();
out.write("服务端 你好".getBytes());
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
public class H_12TcpServer {
public static void main(String[] args) throws Exception {
ServerSocket ss=new ServerSocket(10005);
Socket s=ss.accept();
InputStream in=s.getInputStream();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip);
byte[] buf=new byte[1024];
int len=in.read(buf);
System.out.println(new String(buf,0,len));
OutputStream out=s.getOutputStream();
out.write("收到".getBytes());
s.close();
ss.close();
}
}
服务器端显示:192.168.0.100
服务端 你好
客户端显示:
收到
8. TCP练习
需求: 建立一个文本转换服务器
客户端给服务端发送文本,服务端会将文本转成大写再返回给客户端
而且客户端可以在不断地进行文本转换,当客户端输入over时,转换结束。
/*分析:
客户端
1、操作设备上的数据,使用io技术,并按照io的操作规律
客户端的源: 键盘录入
目的:网络设备 (网络输出流)
操作的是文本数据(可以选择字符流)
2、建立服务
3、获取键盘录入
4、将数据发给服务端
5、获取服务端返回大写数据
6、结束,关闭资源
都是文本数据,可以使用字符流进行操作。
问题点:
1、写入流需要刷新
2、需要加入换行符号,不然写入socket中的数据是没有换行的
*/
package day23;
import java.net.*;
import java.io.*;
public class H_13TcpDemo
{
public static void main(String[] args) throws Exception
{
Socket s=new Socket(InetAddress.getLocalHost(),10006);
//建立读取键盘数据的流对象
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
//目的是网络流
BufferedWriter bufwout=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
// PrintWriter pout=new PrintWriter(s.getOutputStream());
//下面直接用 pout.println(line.toUpperCase());
//定义一个Socket读取流,读取服务端返回的大写信息
BufferedReader bufrin=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufwout.write(line);
bufwout.newLine();
bufwout.flush();
String str=bufrin.readLine();
System.out.println("server:"+str);
}
bufr.close();
s.close();
}
}
/*
服务端
1、源:socket读取流
2、目的:socket输入流
3、都是文本,加入缓冲技术
*/
package day23;
import java.net.*;
import java.io.*;
public class H_13TcpServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss=new ServerSocket(10006);
Socket s=ss.accept();
BufferedReader bufrin=new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bufwout=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line=null;
while((line=bufrin.readLine())!=null)
{
System.out.println(line);
bufwout.write(line.toUpperCase());
bufwout.newLine();//加入换行标记,不然读取时无法读到
bufwout.flush();//刷新缓冲区
}
s.close();
ss.close();
}
}