浅谈网络编程技术(TCP、UDP、HTTP)

来源:互联网 发布:linux 文件内容替换 编辑:程序博客网 时间:2024/05/21 07:47

在介绍这三种编程技术之前,先说一下网络编程的三要素:

  1. IP地址:网络中计算机的唯一标识
  2. 端口:正在运行程序的标识(有效的端口区间在0~65535之间,其中0~1024系统使用或保留端口)
  3. 协议:通信的规则
    举一个简单的例子:
    我要和某人说话,这个步骤流程是什么?
    首先,我要找到说话的对象(通过IP地址找到的);
    然后,开始对她说话,怎么说,要对着耳朵说(端口);
    说了什么,I love you,她好像听不懂英文,这时候我没必要讲英文了,说汉语就好,(协议)

*

1、UDP编程*

特点如下:

  • 把数据打包
  • 数据有限制
  • 不建立连接
  • 速度快
  • 不可靠

然后我们通过代码来了解UDP编程:

这段代码是UDP服务端的代码;public class UdpServer {    public static final int PORT = 30000;    // 定义每个数据报的最大大小为4K    private static final int DATA_LEN = 4096;    // 定义接收网络数据的字节数组    byte[] inBuff = new byte[DATA_LEN];    // 以指定字节数组创建准备接受数据的DatagramPacket对象    /**     * 可存储4K数据的数据报文     */    private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);    // 定义一个用于发送的DatagramPacket对象    private DatagramPacket outPacket;    // 定义一个字符串数组,服务器发送该数组的的元素    String[] books = new String[] { "疯狂Java讲义", "轻量级Java EE企业应用实战",            "疯狂Android讲义", "疯狂Ajax讲义" };    public void init() throws IOException {        try (        // 创建DatagramSocket对象        DatagramSocket socket = new DatagramSocket(PORT)) {            // 采用循环接受数据            for (int i = 0; i < 1000; i++) {                // 读取Socket中的数据,读到的数据放入inPacket封装的数组里。                socket.receive(inPacket);                // 判断inPacket.getData()和inBuff是否是同一个数组                System.out.println(inBuff == inPacket.getData());// -----                // 将接收到的内容转成字符串后输出                System.out.println(new String(inBuff, 0, inPacket.getLength()));                // 从字符串数组中取出一个元素作为发送的数据                byte[] sendData = books[i % 4].getBytes();                // 以指定字节数组作为发送数据、以刚接受到的DatagramPacket的                // 源SocketAddress作为目标SocketAddress创建DatagramPacket。                outPacket = new DatagramPacket(sendData, sendData.length,                        inPacket.getSocketAddress());                // 发送数据                socket.send(outPacket);            }        }    }    public static void main(String[] args) throws IOException {        new UdpServer().init();    }}

这是客户端的代码:

public class UdpClient {    // 定义发送数据报的目的地    public static final int DEST_PORT = 30000;    public static final String DEST_IP = "127.0.0.1";//测试本机    // 定义每个数据报的最大大小为4K    private static final int DATA_LEN = 4096;    // 定义接收网络数据的字节数组    byte[] inBuff = new byte[DATA_LEN];    // 以指定字节数组创建准备接受数据的DatagramPacket对象    private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);    // 定义一个用于发送的DatagramPacket对象    private DatagramPacket outPacket = null;    public void init() throws IOException {        try (DatagramSocket socket = new DatagramSocket()) {            // 初始化发送用的DatagramSocket,它包含一个长度为0的字节数组            outPacket = new DatagramPacket(new byte[0], 0, InetAddress.getByName(DEST_IP), DEST_PORT);            // 创建键盘输入流            Scanner scan = new Scanner(System.in);            // 不断读取键盘输入            while (scan.hasNextLine()) {                // 将键盘输入的一行字符串转换字节数组                byte[] buff = scan.nextLine().getBytes();                // 设置发送用的DatagramPacket里的字节数据                outPacket.setData(buff);                // 发送数据报                socket.send(outPacket);                // 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组里。                socket.receive(inPacket);                System.out.println(new String(inBuff, 0, inPacket.getLength()));            }        }    }    public static void main(String[] args) throws IOException {        new UdpClient().init();    }}

2、TCP协议

特点如下:

  • 需要建立连接通道
  • 数据无限制
  • 速度慢
  • 可靠

    这是服务端代码:

public class Server {    public static void main(String[] args) throws IOException {        // 8888监听的端口号        ServerSocket ss = new ServerSocket(8888);        boolean isFlag = true;        while(isFlag) {            // 与客户端对应的socket, 阻塞            Socket socket = ss.accept();            PrintWriter pw = new PrintWriter(socket.getOutputStream());            pw.write("服务端");            pw.close();        }        if (!ss.isClosed()) {            ss.close();        }    }}

这是客户端代码

public class Client {    public static void main(String[] args) throws UnknownHostException, IOException {        // 10.50.8.40        Socket socket = new Socket("127.0.0.1", 8890);//      System.out.println(br.readLine());//      br.close();        new Thread(new ClientThread(socket)).start();        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        String line = null;//      PrintWriter pw = new PrintWriter(socket.getOutputStream());        PrintStream ps = new PrintStream(socket.getOutputStream());        while ((line = br.readLine()) != null) {            // 将用户的键盘输入内容写入Socket对应的输出流//          pw.println(line);//          pw.flush();            System.out.println(line + "----------");            ps.print(line);            ps.flush();        }//      PrintWriter pw = new PrintWriter(socket.getOutputStream());//      pw.println("zhangtao");//      pw.flush();//      pw.close();    }}

其中类ClientThread代码如下:

package com.gb.android.tcp.chat;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;public class ClientThread implements Runnable {    Socket socket;    BufferedReader br;    public ClientThread(Socket socket) throws IOException {        this.socket = socket;        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));    }    @Override    public void run() {        String line = null;        try {            while ((line = br.readLine()) != null) {                System.out.println(line);            }//          br.close();        } catch (IOException e) {            e.printStackTrace();        }    }}

3、HTTP编程

http网络编程有两种,分别是HttpURLConnection和HttpClient:

首先是HttpURLConnection的用法:
一般只需要new出一个URL对象,并出入目标的网络地址,然后调用一下openConnection()方法即可,如下所示:

URL url=new URL"http://www.baidu.com");HttpURLConnection connection=(HttpURLConnection)url.openConnection();

得到HttpURLConnection的实例之后,我们就可以设置一下HTTP请求所使用的方法。常用的方法主要有两个,GET和POST。GET表示希望从服务区哪里了获取数据,而POST则表示希望提交数据给服务器。写法如下:

connection.setRequestMethod("GET");

接下来就可以进行一些自由的定制了,比如设置连接超时、读取超时的毫秒数,以及服务器希望得到的一些消息头等。这部分内容根据自己的实际情况进行编写,实例写法如下:

connection.setConnectTimeOut8000);connection.setReadTimeOut(8000);

之后调用getInputStream()方法就可以获取到服务器返回的输入流了,剩下的任务就是对流的读取,如下:

InputStream in =connection.getInputStream();

最后就可以调用disconnect()方法将这个HTTP连接关闭掉,如下:

connection.disconnect();

根据上面的步骤,很容易写出一个获取网络数据的代码:

开辟了一个线程处理耗时的网络操作

public class HttpClient {    public void getInfo() {        new Thread(new Runnable() {            public void run() {                URL url;                HttpURLConnection connection = null;                try {                    url = new URL("http://www.baidu.com");                    connection = (HttpURLConnection) url.openConnection();                    connection.setRequestMethod("GET");                    connection.setConnectTimeout(8000);                    connection.setConnectTimeout(8000);                    InputStream in = (InputStream) connection.getInputStream();                    BufferedReader reader = new BufferedReader(                            new InputStreamReader(in));                    StringBuilder response = new StringBuilder();                    String line;                    while ((line = reader.readLine()) != null) {                        response.append(line);                    }                } catch (MalformedURLException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                } finally {                    if (connection != null) {                        connection.disconnect();                    }                }            }        }).start();    }}

HttpClient是Apache提供的HTTP网络访问接口,从一开始的时候就被引入到了androidAPI中,他可以完成和HttpURLConnection巨虎一模一样的效果,但两者也有很大的差别:
HttpClient是一个接口,接口无法创建实例,他会创建DefaultHttpClient的实例,如下:

HttpClient HttpClient=new DefaultHttpClient();

`接着可以创建一个GET请求,就可以创建一个HttpGet对象,并传入网络地址然后调用HttpClient的execute()方法即可:

HttpGet httpGet=new HttpGet(“http://www.baidu.com”);httpClient.execute(httpClient);

然而POST’请求会比GET请求复杂一些,需要创建一个HttpPost对象,并传入目标网路的地址,如下:

HttpPost httpPost=new HttpPost(“http://www.baidu.com”);

然后通过一个NameValuePair集合来存放带待提交的参数,并将这个参数传入到一个UrlEncodedFormEntity中,然后调用HttpPost的setEntity()方法将构建好的UrlEncodedFormEntity传入,如下:

List<NameValuePair> params= new ArrayList<NameValuePair>();params.add(new BasicNameValuePair("username","admin"));params.add(new BasicNameValuePair("password","123456"));UrlEncodedFormEntity entity=new UrlEncodedFormEntity(params,"utf-8");httpPost.setEntity(entity);

接下来和HttpGet是一样的,调用HttpClient的execute()方法,并传入HttpPost对象即可:

httpClient.execute();

执行execute()方法之后就会返回一个HttpResponse对象,服务器返回的所有信息都在这里,通常会先取出服务器的返回状态码,如果是200说明请求和响应是成功的 。如下所示:

if(httpResponse.getStatusLine().getStatusCode()==200){//请求和响应成功!}

接下来取出内容可一个调用个getEntity()方法获取到一个HttpEntity实例,然后再用EntityUtils.toString()这个静态方法将HttpEntity转换成字符串;如下:

HttpEntity entity=httpResponse.getEntity();String response=EntityUtils.toString(entity);

注意乱码问题,如果服务器端返回的数据是带有中文的,直接调用EntityUtils.toString()方法转换会出现乱码,这时候转换的时候将字符集指定成utf-8就可以了,如下:

String response =EntityUtils.toString(entity,“utf-8”);

根据上面的步骤很容易写出一个网络请求数据的代码:

package http;import javax.xml.ws.Response;public class HttpClient {    public static void main(String[] args) {        new Thread(new Runnable() {            @Override            public void run() {                HttpClient httpClient=new DefaultHttpClient();                HttpGet httpGet=new HttpGet("http://www.baidu.com");                HttpResponse httpResponse=  httpClient.execute();                if(httpResponse.getStatusLine().getStatusCode()==200){                    //请求和响应成功!                    HttpEntity entity=httpResponse.getEntity();                    String response =EntityUtils.toString(entity,“utf-8”);                    String info=response.toString();                    }            }        }).start();    }}
0 0
原创粉丝点击