------- android培训、java培训、期待与您交流! ----------
TCP和UDP的区别
UDP:
是面向无连接的,它将数据集源和目的封装成数据包中,不需要建立连接;它的每个数据报(Datagram)的大小限制在64k以内;因为无连接,是不可靠的协议;同样因为不需要建立里连接,所以速度快。
应用特点:只求速度快,数据丢失对程序影响不大。
应用程序实例:聊天室工具、视频、网络会议等。
TCP:
需要建立连接,形成传输数据的通道;在连接中进行大量数据传输;通过三次握手协议完成连接,是可靠的协议;因为必须建立连接,所以效率会稍低。(TCP不像UDP需要封包,而且每个包不能超过64k,它可以大量的传输数据)。
应用特点:适合对数据完整性要求高的程序。
应用程序实例:下载程序。
Socket
网络编程其实就Socket编程,Socket是为网络服务的一种机制。(Socket,中文意思为插座) 每个应用程序都有一个Socket通信端点,可以把Socket想象为每个应用程序上的码头。
通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。
UDP传输
UDP两端是发送端和接受端。
DatagramSocket:UDP传输专用的程序通信端点,既能发送也能接受。
DatagramPacket:数据报包,封装了UDP传输的数据报。里边可以设置要发送的目的地IP地址、端口及要发送的数据。
广播地址:每个网段尾数为255的IP地址,例如192.168.1.255.
UDP练习:聊天程序
/*
编写一个聊天程序有接受数据的部分,和发数据的部分。
这两部分需要同时执行。那就需要用到多线程技术。
一个线程控制收,一个线程控制发。
因为收和发动作是不一致的,所以要定义两个run方法,而且run方法要封装到不同的类中
*/
import java.net.*;
import java.io.*;
class Send implements Runnable{
private DatagramSocket ds;
public Send(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
BufferedReader bufr =new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = bufr.readLine())!=null)
{
if("886".equals(line))
break;
byte[] buf=line.getBytes();
//把发送地址,设为广播地址,
InetAddress i = InetAddress.getByName("192.168.1.255");
DatagramPacket dp=new DatagramPacket(buf,0,buf.length,i,10020);
ds.send(dp);
}
ds.close();
}
catch (Exception e)
{
throw new RuntimeException("发送端失败");
}
}
}
class Rece implements Runnable{
private DatagramSocket ds;
public Rece(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
while(true)
{
byte [] buf =new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
System.out.println("ip:"+ip+" data:"+data);
}
}
catch (Exception e)
{
throw new
RuntimeException("接受端失败");
}
}
}
class ChatDemo{
public static void main(String[] args)throws Exception {
DatagramSocket sendSoket = new DatagramSocket();
DatagramSocket receSoket = new DatagramSocket(10020);
new Thread(new Send(sendSoket)).start();
new Thread(new Rece(receSoket)).start();
}
}
TCP传输
TCP的两端对应的是客户端和服务端。
Socket:TCP传输客户端通信端点。
SeverSocket:TCP传输服务端通信端点。
因为TCP需要建立连接,所有Socket客户端一建立就要指定服务端的IP和端口。而在服务端建立时,要设置监听的端口。
TCP连接成功后,在客户端和服务端就会产生网络流。
客户端Socket提供对网络流进行读写的输入流和输出流对象。
服务端操作网络流时,先获取客户端Socket对象,然后利用该Socket的字节输入输出流进行读写操作。
客户端与服务端进行多次交互时,注意阻塞式方法对程序的影响。
ServerSocket(int port, int backlog),这个构造函数中backlog用于指定客户端的最大连接数。
TCP传输中的两个问题
一、客户端与服务端交互时同时阻塞:
当客户端和服务端中都都有多个阻塞式方法时,如果使用缓冲区读取每行,没有刷新并加入换行符时,会导致客户端与服务端同时处于阻塞等待状态。
二、定义文件结束标记:
当上传文件时,客户端把本地文件变成了IO流,并写入网络输出流时,因为去掉了去掉了window加入的结束标记,使得该IO流没有结束标记,导致服务端读取流中数据时,无法结束。这就需要自定义标记。
自定义标记有三种方法:
1.定义”over”这样的字符结束标记;
2.盖时间戳。
3.使用Socket的shutdownOutput( )和shutdownInput()方法。
示例代码:简单建立TCP客户端和服务端
/*
演示TCP传输。
1.tcp分客户端和服务端。
2.客户端对应的对象是Socket。服务端对应的对象是SeverSocket
*/
/*
客户端:
通过查阅Socket对象,发现在该对象建立时,就可以连接指定的主机。
因为TCP是面向连接的,所以在建立Socket服务时,就要有服务端存在,并连接成功,形成通路后,在该通道进行数据的传输。
需求:给服务段发送一个文本数据。
步骤:
1.创建Socket服务,并指定要连接的主机和端口。
*/
import java.io.*;
import java.net.*;
class TcpClient {
public static void main(String[] args)
throws Exception {
//1.创建客户端的Socket服务,指定目的主机和端口
Socket s = new Socket("192.168.1.13",10003);
//2.为了发送数据,应该获取Socket流中的输出流。
OutputStream out =s.getOutputStream();
//3.获取输出流后写入数据。
out.write("Tcp ge men lai le".getBytes());
//socket关闭客户端Socket服务,也就关闭了网络流资源。
s.close();
}
}
/*
服务端:
1.建立服务端的Socket服务,通过SeverSocket();并监听一个端口。
2. 获取连接过了的客户端对象。 通过SeverSocket的accept方法。没有就会等,所以这个方法是阻塞式的。
3.客户端如果发过了数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流读取发过了的数据。并打印在控制台上。
4.关闭服务。(可选操作,服务端一般是一直开着的)。
*/
class TcpServer{
public static void main(String[] args) throws Exception {
//建立服务端的socket服务,并监听一个端口
ServerSocket ss = new ServerSocket(10003);
//通过accept方法获取连接过了的客户端对象,这步很关键。这个方法是阻塞式的
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+".........connected");
//获取客户端发过来的数据,那么要使用客户端对象的读取流方法读取对象。这个流是网络流
InputStream in = s.getInputStream();
byte [] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();//关闭客户端
ss.close();//可选操作
}
}