从天津转站北京,爬到中关村到直立行走
Java复习篇六
1.TCP/IP
网络参考模型(层次的细致划分)
OSI参考模型
TCP/IP参考模型
OSI参考模型 TCP/IP参考模型
--------------- -----------------------
应用层
表示层 应用层
会话层
---------------- -------------------
传输层 传输层
---------------- -------------------
网络层 网络层(网际层)
---------------- ------------------
数据链路层
物理层 链路层
--------------- ------------------
网络通讯要素:IP地址(IP对象的类,起名字容易记忆)
端口号
传输协议
以QQ————————————————————————>QQ为例:
找到对方IP,byte最大值为255
数据发送到对方指定的对应程序上,为了标识这些应用程序,所以把这些网络应用程序都用数字进行标识。
通信规则称为协议。
TCP/IP可以用在局/广域网。
本地环回地址 127.0.0.1
IPv6包括字母,数字,
UDP
将数据源和目的封装成数据包中,不需要建立连接。
每个数据报的大小限制在64k内。
因无法连接,是不可靠协议。
不需要建立连接,速度快。
面向无连接,速度快,容易丢包,只管发送,发送到哪里,地址,端口(为了方便称呼这个数字,叫做端口,指逻辑端口)要明确出来。
聊天,网络视频会议,邮局寄送包裹就是udp。
TCP
建立连接,形成传输数据通道
在连接中进行大数据量传输
通过3次握手完成连接,是可靠协议
必须建立连接,效率会稍低,消耗资源
下载就是TCP
Socket 就是为网路服务提供的一种机制。
通信的两端都有socket
网络通信其实就是socket间的通信
数据在两个socket间通过io传输
传输协议不一样
/**
* Socket就是为网络服务提供的一种机制
* 通信的两端都有Socket
* 网络通信其实就是Socket间的通信
* 数据在两个Socket间通过IO传输
* @author xinglefly
* @version 1
*/
public class UdpSend {
public static void main(String[] args) throws Exception{
/*1.找到对方ip
* 2.数据要发送到对方指定的应用程序上。
* 为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识。
* 为了方便称呼这个数字,叫做端口。逻辑端口。
* 3.定义通信规则。这个通讯规则称为协议。
* 国际组织定义了通用协议TCP/IP
*/
/*需求:通过udp传输方式,将一段文字数据发送出去
* 思路:
* 1.建立updsocket服务
* 2.提供数据,并将数据封装到数据包中。
* 3.通过socket服务的发送功能,将数据包发出去。
* 4.关闭资源。
*/
//1.创建udp服务,通过DatagramSocket对象。
DatagramSocket ds = new DatagramSocket();
//2.确定数据,并封装成数据包。DatagramPacket(byte[] buf,int length,InetAddress address,int port)
byte [] by = "udp xuexi le ".getBytes();
DatagramPacket dp = new DatagramPacket(by,by.length,InetAddress.getByName("127.0.0.1"),10000);
//3.通过socket服务,将已有的数据包发送出去。通过send方法。
ds.send(dp);
//4.关闭资源。
ds.close();
}
}
/*
* 需求:定义一个应用程序,用于接收udp协议传输的数据并处理的
* 思路:
* 1.定义updsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识
* 方便于明确哪些数据过来该应用程序可以处理。
* 2.定义一个数据包,因为要存储接收到的字节数据。因为数据包对象中有更多
* 功能可以提取字节数据中的不同数据信息。
* 3.通过socket服务的receive方法将收到的数据存入已定义好的数据包中。
* 4.通过数据包对象的特有功能,将这些不同的数据取出。打印在控制台上。
* 5.关闭资源。
*/
class UdpRece{
public static void main(String[] args)throws Exception{
//1.创建udp socket,建立端点。
DatagramSocket ds = new DatagramSocket(10000);
//2.定义数据包,用于存储数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3.通过服务的receive方法将收到的数据存入数据包中。
ds.receive(dp);
//4.通过数据包的方法获取其中的数据
String ip = dp.getAddress().getHostAddress();
String data = new String (dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(ip+"::"+data+"::"+port);
ds.close();
}
}
package com.blackhorse.xinglefly;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* socket编程中的upd
* 需求:通过upd传输方式,将一段文字数据发送出去。
* 思路:
* 1.建立updsocket服务
* 2提供数据,并将数据封装成数据包中。
* 3.通过socket服务的发送功能,将数据包发出去
* 4.关闭资源
* @author xinglefly
* @version 1
*/
public class UpdSend {
public static void main(String[] args) throws Exception{
//1.创建upd服务,通过DatagramSocket对象
DatagramSocket ds = new DatagramSocket(8888);
//2.确定数据,并封装成数据包。DatagramPacket(byte[] buf,int length,InetAddress address,int port)
byte[] buf = "udp".getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.111.1"),1000);
//3.通过socket服务,将已有的数据包发送出去,通过send方法。
ds.send(dp);
//4.关闭资源
ds.close();
}
}
/**
* 需求:定义一个应用程序,用于接收udp协议传输的数据并处理的。
* 定义udp的接收端
* 思路:
* 1.定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。
* 方便于明确哪些数据过来该应用程序可以处理。
* 2.定义一个数据包,因为要存储接收到得字节数据。因为数据包对象中更多功能可以提取字节数据中的不同数据信息。
* 3.通过socket服务的receive方法将受到的数据存入已定义好的数据包中。
* 4.通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。
* 5.关闭资源。
* @author xinglefly
*
*/
class UpdRece{
public static void main(String[] args)throws Exception{
//1.创建upd socket,建立端点
DatagramSocket ds = new DatagramSocket(10000);
while(true){
//2.定义数据包,用于存储数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3.通过服务的receive方法将收到数据存入数据包中。
ds.receive(dp);//阻塞式方法
//4.通过数据包的方法获取其中的数据
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(ip+"::"+data+"::"+port);
}
//5.关闭资源
// ds.close();
}
}
/**
* 客户端
* 1.服务端点
* 2.读取客户端已有的图片数据
* 3.通过socket输出流将数据发给服务端
* 4.读取服务端反馈信息
* 5.关闭
* @author xinglefly
* @version 1
*/
public class PicTest {
public static void main(String[] args)throws Exception{
if(args.length!=1){
System.out.println("请选择一个jpg格式的图片");
return ;
}
File file = new File(args[0]);
if(!(file.exists() && file.isFile())){
System.out.println("该文件有问题,要么不存在,要么不是文件");
return ;
}
if(!file.getName().endsWith(".jpg")){
System.out.println("图片格式错误,请重新选择");
return ;
}
if(file.length()>1024*1024*5){
System.out.println("文件过大,请选择文件");
return ;
}
Socket s = new Socket("127.0.0.1",3330);
FileInputStream fis = new FileInputStream("c:\\001.jpg");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read())!=-1){
out.write(buf,0,len);
}
//告诉服务端数据已写完
s.shutdownOutput();
}
}
//同步上传
//只要明确了每一个客户端要在服务端执行的代码即可。将代码存入run方法中。
class PicThread implements Runnable{
private Socket s;
PicThread(Socket s){
this.s=s;
}
public void run(){
int count=1;
String ip = s.getInetAddress().getHostAddress();
try{
System.out.println(ip+"...conneted");
InputStream in = s.getInputStream();
File file = new File(ip+"("+(count)+")"+".jpg");
while(file.exists())
file = new File(ip+"("+(count++)+")"+".jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1){
fos.write(buf,0,len);
}
OutputStream out = s.getOutputStream();
}catch(Exception e){
throw new RuntimeException(e+"上传失败");
}
}
}
class PicServer{
public static void mian(String[] args)throws Exception{
/*ServerSocket ss = new ServerSocket(3330);
Socket s = ss.accept();
InputStream in = s.getInputStream();
FileOutputStream fos = new FileOutputStream("c:\\server.jpg");
byte[] by = new byte[1024];
int len = 0;
while((len=in.read())!=-1){
fos.write(by,0,len);
}
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
s.close();
ss.close();*/
ServerSocket ss = new ServerSocket(3330);
while(true){
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
}
}
import java.io.*;
import java.net.*;
import java.util.*;
/**
* 编写一个聊天程序
* 有收据的部分,和发行数据的不封
* 这两部分需要同时执行
* 那就需要用到多线程技术
* 一个线程控制收,一个线程控制发
* 因为收和发动作是不一致的,所以要定义两个run方法。
* 而且这两个方法要封装在不同的类中。
* @author xinglefly
* @version 1
*/
class Send implements Runnable{
private DatagramSocket ds;
Send(DatagramSocket ds){
this.ds=ds;
}
public void run(){
BufferedReader br = null;
try{
br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=br.readLine())!=null){
if("886".equals(line))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),1515);
ds.send(dp);
}
}catch(Exception e){
throw new RuntimeException("发送端失败");
}
}
}
class Rece implements Runnable{
private DatagramSocket ds;
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());
int port = dp.getPort();
System.out.println(ip+"::"+data+"::"+port);
}
}catch(Exception e){
throw new RuntimeException("接收端失败");
}
}
}
public class ChatDemo {
public static void main(String[] args)throws Exception{
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receSocket = new DatagramSocket();
new Thread(new Send(sendSocket)).start();
new Thread(new Rece(receSocket)).start();
}
}
import java.util.*;
import java.io.*;
import java.net.*;
/**
* 演示tcp的传输的客户端和服务端的互访。
* 需求:客户端给服务端发送数据,服务端收到后,给客户反馈信息。
* @author xinglefly
* @version 1
*/
public class TcpClient2 {
/*客户端
* 1.建立socket服务。指定要连接主机和端口。
* 2.获取socket流中的输出流。将数据写到该流中。通过网络发送给服务端。
* 3.获取socket流中的输入流,将服务端反馈的数据获取到,并打印。
* 4.关闭客户端资源。
*/
public static void main(String [] args)throws Exception{
Socket s = new Socket("127.0.0.1",3304);
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));
}
}
import java.util.*;
import java.io.*;
import java.net.*;
/**
* 需求:建立一个文本转换服务器
* 客户端给服务端发送文本,服务端会将文本装换成大写在返回给客户端。
* 而且客户端可以不断的进行文本转换,当客户端输入over时,转换结束。
* 分析:
* 客户端:
* 既然是操作设备上的数据,那么就可以食用io技术,并按照io的操作规律来思考。
* 源:键盘录入。
* 目的:网络设备,网络输出流。
* 而且操作的是文本数据,可以选择字符流。
* 步骤:
* 1.建立服务
* 2.获取键盘录入
* 3.将数据发给服务端
* 4.后去服务端返回的大写数据。
* 5.结束,关资源。
* 都是文本数据,可以食用字符流进行操作,同事提高效率,加入缓冲。
* @author xinglefly
* @version 1
*/
public class TransClient {
public static void main(String[] args)throws Exception{
Socket s = new Socket("127.0.0.1",3300);
//定义读取键盘数据的流对象。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//定义目的,将数据写入到socket输出流,发给服务器
// BufferedWriter bufout = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
//定义一个socket读取流,读取服务端返回的大写信息
BufferedReader bufin = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
out.println(line);
/* bufout.write(line);
bufout.newLine();
bufout.flush();
*/ }
}
}
class TransSever{
public static void main(String[] args)throws Exception{
ServerSocket ss = new ServerSocket(3300);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");
//读取socket读取流中的数据。
BufferedReader bufin = new BufferedReader(new InputStreamReader(s.getInputStream()));
//目的。socket输出流,将大写数据写入到socket输出流,并发送给客户端。
// BufferedWriter bufout = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null;
while((line=bufin.readLine())!=null){
out.println(line);
/*bufout.write(line.toUpperCase());
bufout.newLine();
bufout.flush();*/
}
s.close();
ss.close();
}
}
/*该例子出现的问题。
* 现象:客户端和服务端都在莫名的等待。
* 为什么呢?
* 因为客户端和服务端都有阻塞式方法。这些方法没有读到结束标记,那么就一直等
* 而导致两端都在等待。
*
*/
一下是个人自学中的一点心得(经验还是谈不上的),希望能帮到广大跟我一起 愤痘 的程序猿们(传说中的攻城师)。
废话不多说,来看个例子,就拿Android开发中Intent间的传值来说吧。
举例说我想要做的一个事情是,在一个主界面(主Activity)上能连接往许多不同子功能模块(子Activity上去),当子模块的事情做完之后就回到主界面,或许还同时返回一些子模块完成的数据交给主Activity处理。
现在回头看看这个例子,一边吃饭一边做了个小小的总结
见附件图片
随着Windows8的发布,微软给出了一个Windows Runtime(以下简称WinRT),据说是用COM技术实现的。在结合使用.NET和WinRT时,你会发现它们对相同的概念,有不同的实现,或者说是类,比如异步操作,.NET中用Task概念,而WinRT则是用IAsyncInfo,IAsyncAction等,而在流的概念中,.NET围绕Stream类建立,而WinRT则先定义了三个主要的接口,然后逐一实现之。本文就是集中在“流”的相互转换上,因为你在编写Metro App时,会用到WinRT组件。
首先,.NET的Stream可谓是集读、写以及流定位于一身的一个类,那么在WinRT中则将它抽象成三个不同的接口,分别为:IInputStream、IOutupStream和IRandomAccessStream,其实这三个接口就是对应Stream所提供的功能。当然还有别的接口,这里暂不介绍。还有一个要介绍的是IBuffer,这个接口提供了对我们传统放置字节数组的byte[]的抽象,而且只提供了Capcity和Length两个属性(没有方法),Capcity是说这个IBuffer能够容纳多少字节,而Length则说明实际有多少字节,WinRT中也会有一个实现了该接口的类,称为Buffer,我们使用输入输出流时,都会用到。
然后,我们在转换时,最好加入System.IO命名空间,这个空间提供了我们需要的转换的扩展方法。
1. 将IBuffer转换成一个.NET Stream:
由于已经知道了一个字节块(IBuffer),那么我们可以把它放入到一个内存的随机访问流中,就是从Buffer中读取byte到内存流中(InMemoryRandomAccessStream,它实现了上诉的三大接口),再通过扩展方法转换成Stream,代码如下
InMemoryRandomAccessStream memoryStremWRT = new InMemoryRandomAccessStream(); await memoryStremWRT.ReadAsync(buffer,buffer.Length,InputStreamOptions.None); Stream stream = memoryStremWRT.AsStream();
2.将一个IOutputStream转换成为Stream:
stream = outputStream.AsStreamForWrite();
3.将一个IInputStream转换成Stream:
stream = inputStream.AsStreamForRead();
4.将IRandomAccess转换成Stream:
stream=randomAccess.AsStream();
5.Stream 转成Buffer:
由于buffer需要读取数据,所以要一个输入流,此处使用DataReader来加载,它的构造参数就是一个输入流。
IBuffer buffer=null; var inputstream=stream.AsInputStream(); using(var dataReader=new DataReader(inputstream)) { await dataReader.LoadAsync((uint)stream.Length); buffer=dataReader.DetachBuffer(); }
6.Stream 转成IIputStream
var inputstream=stream.AsInputStream();
7.Stream转成IOutputStream
var outputstream=stream.AsOutputStream();
8.Stream转成 IRandomAccess:
此处没有直接提供扩展方法,所以我们的思路还是先构造出一个输入流来获取数据:
IBuffer buffer=null; var inputstream=stream.AsInputStream(); using(var dataReader=new DataReader(inputstream)) { await dataReader.LoadAsync((uint)stream.Length); buffer=dataReader.DetachBuffer(); } var randomAccessStream =new InMemoryRandomAccessStream (); await randomAccessStream.WriteAsync(buffer);
以上用到了DataReader类,对应的还有DataWriter类,这两个类和.NET中的StreamReader和StreamWriter的用法和概念一样,使用了适配器模式,将我们平时用到的类型,比如文本啊,整形数据啊,输入到流或者从流中读出,那么底层的字符,或者整形与byte之间的转换就不需要我们操心了,最多我们要指明是用大端还是小端表示,或者使用什么字节编码。
对于DataReader的含义,就是说我们要从一个输入流中读取数据(数据源是输入流,目标是从流中组装的具体变量值),至于数据的具体含义,那么就看你自己的需求了,一般情况下你是知道流到底是应该编码成string,还是组成int,long,亦或是两者都有,只要顺序搞对就行。
对于DataWriter的含义,则与Reader相对,就是我们输入我们需要的数据,无论是byte,还是string 还是int,long,经过适度的编码以及分解,然后输出到一个流中。
以上的参考代码如下:
// Initialize the in-memory stream where data will be stored. using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { // Create the data writer object backed by the in-memory stream. using (var dataWriter = new Windows.Storage.Streams.DataWriter(stream)) { dataWriter.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8; dataWriter.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; // Parse the input stream and write each element separately. string[] inputElements = ElementsToWrite.Text.Split(';'); foreach (string inputElement in inputElements) { uint inputElementSize = dataWriter.MeasureString(inputElement); dataWriter.WriteUInt32(inputElementSize); dataWriter.WriteString(inputElement); } // Send the contents of the writer to the backing stream. await dataWriter.StoreAsync(); // For the in-memory stream implementation we are using, the flushAsync call // is superfluous,but other types of streams may require it. await dataWriter.FlushAsync(); // In order to prolong the lifetime of the stream, detach it from the // DataWriter so that it will not be closed when Dispose() is called on // dataWriter. Were we to fail to detach the stream, the call to // dataWriter.Dispose() would close the underlying stream, preventing // its subsequent use by the DataReader below. dataWriter.DetachStream(); } // Create the input stream at position 0 so that the stream can be read // from the beginning. using (var inputStream = stream.GetInputStreamAt(0)) { using (var dataReader = new Windows.Storage.Streams.DataReader(inputStream)) { // The encoding and byte order need to match the settings of the writer // we previously used. dataReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8; dataReader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; // Once we have written the contents successfully we load the stream. await dataReader.LoadAsync((uint)stream.Size); var receivedStrings = ""; // Keep reading until we consume the complete stream. while (dataReader.UnconsumedBufferLength > 0) { // Note that the call to readString requires a length of "code units" // to read. This is the reason each string is preceded by its length // when "on the wire". uint bytesToRead = dataReader.ReadUInt32(); receivedStrings += dataReader.ReadString(bytesToRead) + "\n"; } // Populate the ElementsRead text block with the items we read // from the stream. ElementsRead.Text = receivedStrings; } }