序言
从我们的最开始使用的HttpClient到HttpURLConnection,当然现在如果还在说你在项目中自己封装使用它们两个,有点多余了,无论是Volley还是OkHttp都是要比其好很多的,写起来方便,效率高,你就是要造轮子,这个就无法阻挡你了,拥有一个造轮子的心,还要记得,性非议也善假于物也。今天回顾下,基本使用,然后从一个post到网络端接收的一个处理过程,进行一个分析,让我们对于其底层的实现有所了解。而现在,HttpClient已经被弃用,所以这里也不再讲,来讲下HttpURLConnection。
HttpURLConnection
HttpURLConnection相比于HttpClient,其API简单,体积小,而且其压缩和缓存机制可以有效的减少网络访问的流量,在提升速度和省电方面都很有优势,
public void sendRequest(String url) throws IOException{
InputStream is = null;
try{
URL newUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)newUrl.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(10000);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Connection", "Keep-Alive");
String data = "username=jensea";
OutputStream out = conn.getOutputStream();// 获得一个输出流,向服务器写数据
out.write(data.getBytes());
out.flush();
out.close();
conn.connect();
is = conn.getInputStream();
String result = convertStreamToString(is);
}catch (IOException e){
}finally {
is.close();
}
}
private String convertStreamToString(InputStream is) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try{
while((line=reader.readLine())!=null){
sb.append(line+"/n");
}
}catch (IOException e){
e.printStackTrace();
}
return sb.toString();
}
从客户端到服务端看网络请求实现
对于客户端和服务端,其实现无非是通过对Socket进行读写,然后对其进行解析,根据解析内容作出响应,然后客户端从自己的socket缓冲区中读取信息,而我们所使用的HttpClient,HttpURLConnection则是对其一个封装,将其中的流读写的细节进行了一个隐藏,而我们的Volley,OkHttp则是在其基础上,结合线程池进行了一个更高效的封装。
服务端
public class SimpleHttpServer extends Thread {
public static final int HTTP_PORT = 8000;
ServerSocket mSocket = null;
public SimpleHttpServer(){
try{
mSocket = new ServerSocket(HTTP_PORT);
}catch (IOException e){
e.printStackTrace();
}
if(mSocket == null){
throw new RuntimeException("服务器Socket初始化失败");
}
}
@Override
public void run() {
try {
while(true){
System.out.print("等待连接中");
new DeliverThread(mSocket.accept()).start();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
绑定制定端口套接字
等待连接请求,创建处理线程
对于具体的请求内容处理交给了Deliver线程
public class DeliverThread extends Thread {
Socket mClientSocket;
BufferedReader mInputStream;
PrintStream mOutputStream;
//请求方法
String httpMethod;
String subPath;
String boundary;
//请求参数
Map<String, String> mParams = new HashMap<String, String>();
Map<String, String> mHeaders = new HashMap<String, String>();
boolean isParseHeader = false;
public DeliverThread(Socket socket) {
mClientSocket = socket;
}
@Override
public void run() {
try {
mInputStream = new BufferedReader(new
InputStreamReader(mClientSocket.getInputStream()));
mOutputStream = new PrintStream(mClientSocket.getOutputStream());
parseRequest();
handleResponse();
} catch (IOException e) {
}
}
//处理请求,读出每一行,确定是头部,还是请求体,然后交给不同的函数处理
private void parseRequest() {
String line;
try {
int lineNum = 0;
while ((line = mInputStream.readLine()) != null){
if(lineNum==0){
parseRequestLine(line);
}
if(isEnd(line)){
break;
}
if(lineNum!=0&&!isParseHeader){
parseHeader(line);
}
//头部被处理完,处理请求参数
if(isParseHeader){
parseRequestparams(line);
}
lineNum++;
}
} catch (IOException e) {
e.printStackTrace();
}
}
//处理请求行,请求方法+空格+HTTP版本号
private void parseRequestLine(String lineOne) {
String[] tmpStrings = lineOne.split(" ");
httpMethod = tmpStrings[0];
subPath = tmpStrings[1];
}
//处理头部
private void parseHeader(String headLine) {
if (headLine.equals("")) {
isParseHeader = true;
return;
} else if (headLine.contains("boundary")) {
boundary = parseSecondField(headLine);
}else{
parseHeaderParam(headLine);
}
}
private String parseSecondField(String line) {
String[] headerArray = line.split(";");
parseHeaderParam(headerArray[0]);
if(headerArray.length>1){
return headerArray[1].split("=")[1];
}
return "";
}
//处理头部每一个参数,然后将其添加到mHeaders中
private void parseHeaderParam(String headerLine) {
String[] keyvalue = headerLine.split(":");
mHeaders.put(keyvalue[0].trim(), keyvalue[1].trim());
}
//处理请求参数
private void parseRequestparams(String paramLine) throws IOException{
if(paramLine.equals("--"+boundary)){
String ContentDisposition = mInputStream.readLine();
String paraName = parseSecondField(ContentDisposition);
mInputStream.readLine();
String paramvalue = mInputStream.readLine();
mParams.put(paraName,paramvalue);
}
}
//根据传递的参数进行相应的处理
private void handleResponse(){
mOutputStream.println("HTTP/1.1 200 OK");
mOutputStream.println("Content_Type:application/json");
mOutputStream.println();
mOutputStream.println("{\"stcode\":\"success\"}");
]
}
上述代码设计到一些字符串的处理,相对也比较简单,对于其中请求参数的处理,你可能会感觉有点难懂。首先要明白对于其要处理的数据中,请求的数据格式是怎么样的。
--DFDFJD3243dfddfdfdffdf
content-Disposition:form-data; name="username"
Mr.Simple
通过其格式,再去回顾一下上面的处理方式就不难看懂了。
客户端
public class HttpPost {
public String url;
private Map<String,String> mParamsMap = new HashMap<String,String>();
Socket mSocket;
public HttpPost(String url){
this.url = url;
}
public void addParam(String key,String value){
mParamsMap.put(key,value);
}
public void execute(){
try{
mSocket = new Socket(this.url,SimpleHttpServer.HTTP_PORT);
PrintStream outputStream = new PrintStream(mSocket.getInputStream());
BufferedReader inputStream = new BufferedReader(new InputStreamReader(mSocket
.getInputStream()));
final String boundary = "my_boundary_123";
writeHeader(boundary,outputStream);
writeParams(boundary,outputStream);
waitResponse(inputStream);
}catch (UnknownHostException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}finally {
mSocket.close();
}
}
private void writeHeader(String boundary,PrintStream outputStream){
outputStream.println("POST /api/login/ HTTP/1.1");
outputStream.println("content-length:123");
outputStream.println("Host:"+this.url);
outputStream.println("boundary="+boundary);
outputStream.println("Uset-Agent:android");
outputStream.println();
}
private void writeParams(String boundary,PrintStream outputStream){
Iterator<String> paramsKeySet = mParamsMap.keySet().iterator();
while(paramsKeySet.hasNext()){
String paramName = paramsKeySet.next();
outputStream.println("--"+boundary);
outputStream.println("Content-Disposition:form-data; name="+paramName);
outputStream.println();
outputStream.println(mParamsMap.get(paramName));
}
outputStream.println("--"+boundary+"--");
}
private void waitResponse(BufferedReader inputStream) throws IOException{
String responseLine = inputStream.readLine();
while(responseLine==null||!responseLine.contains("HTTP")){
responseLine = inputStream.readLine();
}
while((responseLine=inputStream.readLine())!=null){
System.out.println(responseLine);
}
}
}
代码量不大,创建socket,然后向socket中,写入头部,请求参数,等待服务器的回应,但是这个过程中,socket又干了些什么呢?socket又是个什么呢?这个可以参考我前面对于网络和Linux下进程通信的文章。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。