--------- android培训、java培训、期待与您交流! ----------
黑马程序员---网络编程技术
网络通讯的方式主要有两种:
1、 TCP(传输控制协议)方式
2、 UDP(用户数据报协议)方式
为 了方便理解这两种方式,还是先来看一个例子。大家使用手机时,向别人传递信息时有两种方式:拨打电话和发送短信。使用拨打电话的方式可以保证将信息传递给 别人,因为别人接听电话时本身就确认接收到了该信息。而发送短信的方式价格低廉,使用方便,但是接收人有可能接收不到。
在网络通讯中,TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。而UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得。
这两种传输方式都是实际的网络编程中进行使用,重要的数据一般使用TCP方式进行数据传输,而大量的非核心数据则都通过UDP方式进行传递,在一些程序中甚至结合使用这两种方式进行数据的传递。
由于TCP需要建立专用的虚拟连接以及确认传输是否正确,所以使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些。
OSI参考模型的全称是开放系统互连参考模型,它是由国际化标准组织ISO提出的一个网络系统互连模型。ISO组织把网络通讯工作分为7层,一到四层被认为是低层, 这些层与数据移动密切相关,5到7层是高层,包含应用程序级的数据,每一层负责一项具体的工作,然后把数据交给下一层。
InetAddress:
用于描述IP的类,主要方法有:
String getHostAddress();:返回对象IP地址的字符串形式
String getHostName(); :返回对象的主机名
static InetAddress getLocalHost():获取本地主机对象
static InetAddress getByName("IP地址"):获取IP地址或者域名获取主机对象。
static InetAddress[] getAllByAddress("域名"):通过主机名或者域名获取不同IP地址的主机对象数组。
注:如果IP地址和对应的主机名这个映射关系没有在网络上,其他主机通过IP地址去搜索到了,但是会有没解释成功的情况,getHostName()获取的还是IP的地址;getHostName();会有一个解释过程。
当输入域名用getByName方法获取主机对象时,IP地址并不是唯一的。因为网络上的服务器可能有多台,对应不用的IP地址,这时就要用:getAllByAddress方法。大部分用getAllByAddress方法为主,因为getHostName方法需要解释。
UDP、TCP和Socket
UDP: 1.将数据及源和谜底封装在数据包中,不需要建立连接
2.每个数据的大小控制在64k内
3.因无连接,是不可靠协议
4.不需要建立连接,速度快
TCP: 1. 需要建立连接,形成传输数据的通道
2.在连接中进行大量数据传输
3.通过三次握手完成连接,是可靠协议
4.必须要建立连接,效率稍低
Socket 套接字:1. Socket 是为网络服务提供的一种机制
2. 通信的两端都要具有Socket
3. 网络通信其实就是Socket 间的通信
4.数据在两个Socket 间通过IO传输
个人理解可以将Socket 理解成码头,A城市的码头将货物运到B码头通过河流运输,A城市电脑A,B城市电脑B,码头:Socket ,货物就是数据,河流就是IO流
UDP传输:
1、定义UDPSocket服务,通常会监听一个端口,其实就是给这个接收网络应用程序定义数字标识。方便于明确哪些数据传输过来后是该应用程序可以处理的。
2、定义一个空的数据包,用于存储接收到的字节数据。因为数据包对象中有更多的功能可以崎岖字节数据中的同数据信息。
3通过Socket服务的receive方法接收到的数据存入已定义好的数据包中。
4、通过数据包对象的特有功能,将这些不同的数据取出。
5、关闭资源。
注意:不手动定义端口的话,虚拟机会自动添加一个端口,但是就会和发送端定义的端口对应不上,就接收不到数据。另外,DatagramPacket中的getPort()是获取发送端的自身的端口,而不是发送端的目的端口。
)
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket(11111);
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
String str = null;
while(true)
{
ds.receive(dp);
str = new String(buf,0,dp.getLength());
String ip = dp.getAddress().getHostAddress();
System.out.println(ip+"::"+str);
}
}
TCP传输:
建立客户端和服务端,建立连接后,通过socket的IO流进行数据传输。
对客户端和服务端的理解:
客户端:
该对象建立时,就可以去连接指定主机,因为TCP是面向连接的,所以在建立Socket服务时,只要有服务在并连接成功形成通路后,该通道进行数据的传输
服务端:
1. 建立服务端的Socket服务,ServerSocket(), 并监听一个端口
2. 获取连接过来的客户端对象,通过ServerSocket的accept方法,没有连接就会等,所以这个方法是阻塞式的。
3.如果客户端发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发来的数据
4.关闭服务器
/*
演示tcp的传输的客户端和服务端的互访。
需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
*/
/*
客户端:
1,建立socket服务。指定要连接主机和端口。
2,获取socket流中的输出流。将数据写到该流中。通过网络发送给服务端。
3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印。
4,关闭客户端资源。
*/
import java.io.*;
import java.net.*;
class myServer2
{
public static void main(String[] args) throws Exception
{
//建立服务端
ServerSocket server = new ServerSocket(10022);
while(true)
{
//获取客户端对象
Socket s = server.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"...连接服务器!");
//客户端对象输出流和读取流
//BufferedWriter bfos = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
BufferedReader bfis = new BufferedReader(new InputStreamReader(s.getInputStream()));
//简化代码不用BufferedWriter和转换流,用PrintWriter;
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
//循环获取客户端信息和进行反馈
while(true)
{
String line = bfis.readLine();//当客户端关闭,这里就会返回-1
if("over".equals(line))
break;
System.out.println(ip+"::"+line);
pw.println(line.toUpperCase());
/*
bfos.write(line.toUpperCase());
//跟客户端一样,要加上,不然客户端那里也是等待
bfos.newLine();
bfos.flush();
*/
}
System.out.println(ip+"...以结束连接!");
s.close();
}
}
}
class myTcpDemo2
{
public static void main(String[] args) throws Exception
{
//客户端连接
Socket sock = new Socket("192.168.2.100",10022);
//获取键盘录入
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
//客户端输出流和读取流
//BufferedWriter bfos = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
BufferedReader bfis = new BufferedReader(new InputStreamReader(sock.getInputStream()));
//简化代码不用BufferedWriter和转换流,用PrintWriter;
PrintWriter pw = new PrintWriter(sock.getOutputStream(),true);
String line = null;
while((line=bfr.readLine())!=null)
{
if("over".equals(line))
{
pw.println(line);
/*
bfos.write(line);
bfos.flush();*/
break;
}
pw.println(line);
/*
bfos.write(line);
//这里要加上newLine方法,不然服务端那里的readLine方法没有读取到换行,就会一直等待
bfos.newLine();
bfos.flush();
*/
String str = bfis.readLine();
System.out.println("Server::"+str);
}
bfr.close();
sock.close();
}
}