----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
1.网络模型
OSI七层参考模型
物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。
TCP/IP模型
网络接口层,网络层,传输层,应用层
数据通信主要用到ip地址和端口号组成的套接字,网络通信的实质是Socket之间的通信。
2.UDPSocket通信建立
Socket标示具有唯一性,网络通信根据ip地址找到特定的主机,再根据端口号找到相关程序的进程或线程。
DatagramSocket的几个常用构造方法:
DatagramSocket() 构造数据报套接字并将其绑定到本地主机上任何可用的端口。该端口号是随机绑定的。
DatagramSocket(int port) 创建数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket(int port,InetAddress laddr) 创建数据报套接字,将其绑定到指定的本地地址。
DatagramSocket(SocketAddress bindaddr) 创建数据报套接字,将其绑定到指定的本地套接字地址。通过SocketAddress的子类InetSocketAddress(InetAddress addr, int port) 创建实例参数。
DatagramSocket()的send和receive方法是阻塞方法,如果监听端口没有数据,则receive处于等待状态,如果接收到数据,则唤醒。
DatagramPacket的构造方法
分为接收数据的数据报和发送数据的数据报两类构造方法。
DatagramPacket(byte[] buf, int length) 构造 DatagramPacket
,用来接收长度为length
的数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构造数据报包,用来将长度为length
的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int offset, int length) 构造 DatagramPacket
,用来接收长度为length
的包,在缓冲区中指定了偏移量。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 构造数据报包,用来将长度为length
偏移量为offset
的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造数据报包,用来将长度为length
偏移量为offset
的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int length, SocketAddress address) 构造数据报包,用来将长度为length
的包发送到指定主机上的指定端口号。
发送数据的数据报必须包含套接字(ip+端口号)相关信息。
3.利用两个线程模拟UDP通信时,创建Rend和Receive类,需要通过构造方法传递DatagramSocket参数,在run方法中实现需要的业务。.BufferedReader类:从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。通过控制台输入(System.in)将数据放入BufferedReader缓冲区中,然后通过行读取方法,将数据封装到数据包中,然后通过Socket的Send方法将数据发送到指定主机的对应的端口号。
例如:
class UdpSend {
public static void main(String[] args) throws IOException {
//创建UDP服务,通过DatagramSocket对象
DatagramSocket ds=new DatagramSocket(new InetSocketAddress(InetAddress.getByName("192.168.1.100"), 10003));
//创建数据包,通过DatagramPacket对象
//byte[] data ="hello world".getBytes();
BufferedReader bf =new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=bf.readLine())!=null){
if("886".equals(line))
break;
byte[] buf=line.getBytes();
DatagramPacket dp=new DatagramPacket(buf, 0,buf.length,InetAddress.getByName("192.168.1.100"),10000 );
//通过Socket方法发送
ds.send(dp);
}
//释放资源
ds.close();
}
}
/*
* 需求:创建一个应用程序,用于接收发送端传输的数据
*步骤:
*1.定义udpSocket服务
*2.创建DatagramPacket包,用UDPSocket的recevie方法将数据封装到DatagramPacket包中
*3.利用封装对象的特有方法,取出相关的数据。并打印在控制台上。
*4.关闭资源
*/
class UDPRecive{
public static void main(String[] args) throws IOException{
//创建UDPSocket服务
DatagramSocket ds=new DatagramSocket(10000);
while(true){
//定义接收的数据包
byte[] buf=new byte[1024];
DatagramPacket dp= new DatagramPacket(buf,0, buf.length);
//通过服务的Receive方法存放到数据包中
ds.receive(dp);
String ip=dp.getAddress().getHostAddress();
byte[] data=dp.getData();
String dataString =new String(data,0,dp.getLength());
int port = dp.getPort();
System.out.println(ip+":"+dataString+"--"+port);
}
}
}
4.TCP传输
客户端(Socket)和服务端(ServerSocket),建立连接后通过Socket的IO流进行数据传输,关闭Socket。客户端和服务端是两个独立的应用程序。
5.Socket类
Socket通路一建立,流就已经存在了,这是Socket内部封装好的。
Socket类的构造方法
Socket()通过系统默认类型的SocketImpl 创建未连接套接字。通过connect(SocketAddress endpoint, int timeout) 方法将此套接字连接到具有指定超时值的服务器上,并通过实现SocketAddress的子类InetSocketAddress方法,建立Socket封装。
Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。
ServerSocket(int port) 创建绑定到特定端口的服务器套接字。
ServerSocket通过accept方法得到客户端的Socket对象,获得他的流对象,然后再和客户端进行通信。服务器端只有开通监听端口号,客户端才可以成功发送,否则客户端发送会报ConnectException。当客户端通过InputStream的read方法读取服务端的输出流时,因为read方法是阻塞式方法,没有读到数据,会一直等待。所以程序会一直等待有数据读入完成后,才会执行后面的语句。
当客户端和服务端出现莫名的等待是,需要查看阻塞式方法,这些方法有没有读到结束标记。带有缓冲区的流对象,需要通过刷新,才能将数据装入到流中。
例如:
class TCPClient{
public static void main(String[] args) throws Exception{
Socket sk =new Socket();
//通过connect方法连接
sk.connect(new InetSocketAddress(InetAddress.getByName("192.168.1.100"),10009));
//为了发送数据需要获得Socket流的输出流
OutputStream out =sk.getOutputStream();
//数据会写入到输出流中去,并随着网络发送到服务端
out.write("tcp come in".getBytes());
sk.close();
}
}
/*
需求:定义端点接受数据并打印在控制台上
1.通过ServerSocket建立服务端Socket
2.获得客户端的对象。通过accept方法实现,这个方法是阻塞式的,没有连接就会等。
3,客户端如果发送过来数据,服务端需要用对于的客户端对象,用客户端对象会的输入流对象,并打印到控制台
4.关闭服务(可选操作)
*/
class TCPServe{
public static void main(String[] args) throws Exception{
ServerSocket ss =new ServerSocket(10009);
while(true){
Socket sk =ss.accept();
String ip =sk.getInetAddress().getHostAddress();
System.out.println(ip+"connect");
InputStream ips =sk.getInputStream();
byte[] buf=new byte[1024];
int len =ips.read(buf);
System.out.println(new String(buf,0,len));
sk.close();
}
}
6.TCP上传图片
shutdownOutput() 通过此方法告诉套接字的输出流已经使用完毕,加上使用标记。处理流时如果没有加上结束标记,会一直循环,不会结束。多用户上传图片时,需要将客户端封装到线程当中,线程会随机的获取cpu的执行权限,从而实现多用户上传。
class TCPClient{
public static void main(String[] args) throws Exception{
Socket sk =new Socket();
//通过connect方法连接
sk.connect(new InetSocketAddress(InetAddress.getByName("192.168.1.100"),10009));
//为了发送数据需要获得Socket流的输出流
FileInputStream fis=new FileInputStream("1.gif");
OutputStream ops=sk.getOutputStream();
byte[] buf=new byte[1024];
int len;
while((len=fis.read(buf))!=-1){
ops.write(buf, 0, len);
}
sk.shutdownOutput();
InputStream ips=sk.getInputStream();
byte[] bufr =new byte[1024];
ips.read(bufr);
String ref=new String(bufr,0,bufr.length);
System.out.println(ref);
fis.close();
sk.close();
}
}
/*
需求:定义端点接受数据并打印在控制台上
1.通过ServerSocket建立服务端Socket
2.获得客户端的对象。通过accept方法实现,这个方法是阻塞式的,没有连接就会等。
3,客户端如果发送过来数据,服务端需要用对于的客户端对象,用客户端对象会的输入流对象,并打印到控制台
4.关闭服务(可选操作)
*/
class TCPServe{
public static void main(String[] args) throws Exception{
ServerSocket ss =new ServerSocket(10009);
while(true){
Socket sk =ss.accept();
String ip =sk.getInetAddress().getHostAddress();
FileOutputStream fos=new FileOutputStream("2.bmp");
InputStream ips =sk.getInputStream();
byte[] buf=new byte[1024];
int len;
while((len=ips.read(buf))!=-1){
fos.write(buf, 0, len);
}
OutputStream out=sk.getOutputStream();
out.write("上传成功".getBytes());
sk.close();
}
}
}
7.浏览器作为客户端
class ServerDemo
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(11000);
while(true){
Socket s =ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+">>>已连接");
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("<html><body>自定义浏览器</body></html>");
s.close();
}
//ss.close();
}
}
在浏览器地址栏输入:http://localhost:11000/
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------