1、Http协议
http协议:定义的浏览器向万维网服务器请求万维网文档,以及服务器把文档传递给浏览器。http是面向应用层协议。在万维网上能够可靠的交换文件(包括文本,声音,图像等)。
2、客户端与服务器建立连接流程。
1.客户端 通过发送url发出请求。比如:http://www.baidu.com
- htttp—-请求的协议;(常见的http和https协议)
- www.baidu.com—-通过域名解析的Ip地址(ip地址难以记忆)
- 目录下的文件名等。(可以省略)
2.在服务器收到请求后,做出相应的响应处理,返回成功或者错误的信息,包括MIME信息。
3.客户端在收到服务器返回的信息后通过浏览器显示在屏幕上,然后断开链接。
4、Http与Socket的区别:
http://www.cnblogs.com/lwbqqyumidi/archive/2012/11/04/2754415.html
HTTP:超文本传输协议,首先它是一个协议,并且是基于TCP/IP协议基础之上的应用层协议。TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,HTTP是应用层协议,主要解决如何包装数据。HTTP协议详细规定了浏览器与服务器之间相互通信的规则,是万维网交换信息的基础。HTTP是基于请求-响应形式并且是短连接,并且是无状态的协议。针对其无状态特性,在实际应用中又需要有状态的形式,因此一般会通过session/cookie技术来解决此问题。
Socket:Socket不属于协议范畴,而是一个调用接口(API),Socket是对TCP/IP协议的封装,通过调用Socket,才能使用TCP/IP协议。Socket连接是长连接,理论上客户端和服务器端一旦建立连接将不会主动断开此连接。Socket连接属于请求-响应形式,服务端可主动将消息推送给客户端。
http连接:http连接就是所谓的短连接,即客户端向服务器端发送一次请求,服务器端响应后连接即会断掉;
socket连接:socket连接就是所谓的长连接,理论上客户端和服务器端一旦建立起连接将不会主动断掉;但是由于各种环境因素可能会是连接断开,比如说:服务器端或客户端主机down了,网络故障,或者两者之间长时间没有数据传输,网络防火墙可能会断开该连接以释放网络资源。
Socket适用场景:网络游戏,银行交互,支付。
http适用场景:公司OA服务,互联网服务。
4、建立连接的三次握手
三次握手主要是为了防止过期的链接再次传给被连接的主机。
比如a主机要连接到b主机,a向b发起请求链接,由于某种原因,没有链接上,于是a
又向b发送一条请求,当b 收到a的第二次请求时,建立链接,然后断开。
这时候,a发出的第二条请求也到达b这时候,又进行的连接。其实该连接已经过期。
SYN:同步序列编号(Synchronize Sequence Numbers)
ACK:确认标志(Acknowledgement Number)
三次握手:
第一次握手:客户端发送syn到服务器,等待服务器确认。(syn=x)
第二次握手:服务器收到syn包,必须确认客户端的syn(ack=x+1),同时发送一个自己的syn包syn=y
第三次握手:客户端收到syn+ack后,再次向服务器发送确认包ack(y+1),发送后三次握手完成,建立连接。
5、Http的请求头信息
从浏览器中输入http://www.baidu.com得到下面的信息。
1、请求的内容:
- 请求地址:Remote Address
Remote Address:119.75.217.109:443
- 请求的RUL:Request URL
Request URL:https://www.baidu.com/
- 请求的方式:Request Method
Request Method:GET
- 返回码:Status Code
200 OK
2、请求头内容:
- Accept:浏览器可接受的MIME类型。
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
MIME类型:text/html,application/xhtml+xml,application/xml
Text:文本类型;
text/html:表示html文档;
Application:表示传输应用程序数据或者二进制数据;
application/xhtml+xml表示xhtml文档
application/xml表示xml文档
- Accept-Charset:浏览器接收的字符编码
Accept-Encoding:gzip,deflate(gzip是指可压缩的,deflate是指使用了lz77算法与哈夫曼编码的一个无损数据压缩文件格式)
- Accept-Language:浏览器接收的语言
Accept-Language:zh-CN,zh;q=0.8(zh-ch表示简体中文,zh表示中文,q权重系数,请求更倾向于“;”前的表示内容)
- Cache-Control:是否有缓存
Cache-Control:max-age=0
- Connection*户端与服务器的链接类型
Connection:keep-alive(keep-alive表示持久连接)
2、响应头内容:
- Cache-Control缓存
Cache-Control:private
- Connection:保持链接
Connection:keep-alive
- Content-Encoding:支持的编码
Content-Encoding:gzip
- Content-Type:
Content-Type:text/html;charset=utf-8
6、HttpUrlConnection相关的属性。
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在 http中。
urlConn.setDoOutput(true);
// 设置是否从httpUrlConnection读入,默认情况下是true;
urlConn.setDoInput(true);
// Post 请求不能使用缓存
urlConn.setUseCaches(false);
// 设定传送的内容类型是可序列化的java对象
// (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)
urlConn.setRequestProperty("Content-type","application/x-java-serialized-object");
// 设定请求的方法为"POST",默认是GET
urlConn.setRequestMethod("POST");
// 连接,上面对urlConn的所有配置必须要在connect之前完成,
urlConn.connect();
7、得到向服务器提交数据的上传进度
当我们要获取上传进度的时候,一般会立即显示上传100%的进度,其实文件还在上传。
上面conn的连接中有这样一个配置。有个setUseCaches(false)这样一个属性设置。其实这个值是不起作用的,stackoverflow有许多相关的资料。api上说这个设置没有缓存,但实际上还是有缓存的,比如说向服务器提交图片或者文件,得到的是一个不真实的进度,原因是使用httpurlconnection向服务器提交数据,它都会进行缓存。也就是以这种方式得不到真正的上传进度。
如何得到真实的上传进度。
(1)conn.setUseCahces(false):不起作用。
(2)conn.setChunkedStreamingMode(1024);在api上描述的是可能不适配后台服务器,我测试的php服务器,分段传输也没有作用。
(3)conn.setFixedLengthStreamingMode(contentLength);经测试也没用作用。
(4)换httpclient。
(5)用其他c++的类库。
8、从代码中理解get与post提交数据;
1、get方法实现登陆;
服务器上代码(myeclipse建立web项目,tomcat部署项目):
服务器中的代码如下:
(1)jsp中写出服务器登陆界面。
<body>
This is my JSP page.
<br>
<form action="ServletDemo" method="get">
用户名:<input type="text" id="username" name="username" /> <br>
密码: <input type="text" id="password" name="password" /> <br> <input
type="submit" value="提交" />
</form>
</body>
java代码判读用户名和密码,返回登陆成功或者失败。
public class ServletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
resp.setContentType("text/html;charset=utf-8");
// 浏览器默认的编码是iso-8859-1转换成utf-8,如果不转换,会产生乱码。
String name = new String(username.getBytes("iso-8859-1"), "utf-8");
String pass = new String(password.getBytes("iso-8859-1"), "utf-8");
System.out.println("username" + name);
System.out.println("password" + pass);
//如果登陆名是张三,密码是123,登陆成功,否则登陆失败。
if ("张三".equals(name)&&pass.equals("123")) {
resp.getWriter().write("登陆成功");
} else
resp.getWriter().write("用户名或密码错误");
}
}
在android中请求服务器,从服务器中获取请求的结果,显示登陆成功,或者登陆失败。
public class MainActivity extends Activity {
private EditText et_name;
private EditText et_password;
private Button btn_submit;
private TextView tv_result;
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
tv_result.setText(msg.obj + "");
Toast.makeText(MainActivity.this, (String) msg.obj, 0).show();
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_name = (EditText) findViewById(R.id.et_name);
et_password = (EditText) findViewById(R.id.et_pass);
tv_result = (TextView) findViewById(R.id.tv_result);
btn_submit = (Button) findViewById(R.id.btn_submit);
// 用get的方式请求,把请求内容拼接到url后面。
final String s = "http://192.168.1.103:8080/testServlet/ServletDemo?username=aaaa&password=1234";
//Log.i("MainActivity", path);
btn_submit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
final String username = et_name.getText().toString().trim();
final String password = et_password.getText().toString().trim();
Thread t = new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
final String path = "http://192.168.1.103:8080/testServlet/ServletDemo?username="
+ URLEncoder.encode(username) // 对提交的数据进行url编码
+ "&password="+password;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setReadTimeout(5000);
if (conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
String text = Utils.getTextFromStream(is);
Log.i("MainActivity", text);
// 发送消息,把服务器返回的本文弹出吐司显示
Message msg = handler.obtainMessage();
msg.obj = text;
handler.sendMessage(msg);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.run();
}
};
t.start();
}
});
}
}
工具类代码:
public class Utils {
public static String getTextFromStream(InputStream is){
try {
int len = 0;
byte[] b = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while((len = is.read(b)) != -1){
bos.write(b, 0, len);
}
String text = new String(bos.toByteArray());
bos.close();
return text;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
2、以post的方法提交请求。
package com.example.logindemo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText et_name;
private EditText et_password;
private Button btn_submit;
private TextView tv_result;
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
tv_result.setText(msg.obj + "");
Toast.makeText(MainActivity.this, (String) msg.obj, 0).show();
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_name = (EditText) findViewById(R.id.et_name);
et_password = (EditText) findViewById(R.id.et_pass);
tv_result = (TextView) findViewById(R.id.tv_result);
btn_submit = (Button) findViewById(R.id.btn_submit);
// 用get的方式请求,把请求内容拼接到url后面。
// Log.i("MainActivity", path);
btn_submit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
final String username = et_name.getText().toString().trim();
final String password = et_password.getText().toString().trim();
Thread t = new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
// final String s =
// "http://192.168.1.103:8080/testServlet/ServletDemo?username=aaaa&password=1234";
final String path = "http://192.168.1.103:8080/testServlet/ServletDemo";
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setRequestMethod("POST");
String text = "username="
+ URLEncoder.encode(username) + "&password="
+ password;
conn.setReadTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length",
text.length() + "");
conn.setDoOutput(true);
conn.setDoInput(true);
OutputStream os=conn.getOutputStream();
//把提交的文件写到流中;
os.write(text.getBytes());
if (conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
String s = Utils.getTextFromStream(is);
Log.i("MainActivity", text);
// 发送消息,把服务器返回的本文弹出吐司显示
Message msg = handler.obtainMessage();
msg.obj = s;
handler.sendMessage(msg);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.run();
}
};
t.start();
}
});
}
}
服务器与客户端代码下载地址
http://download.youkuaiyun.com/detail/androidxiaogang/9344051