黑马程序员_Java基础_网络编程

来源:互联网 发布:淘宝lol代练可靠吗 编辑:程序博客网 时间:2024/05/01 17:24

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

一、简介

Java的网络编程提供了两种通讯协议,UDP(数据报协议)与TCP(传输控制协议),网络通讯有三个要素:1、IP地址,2、端口号,3、网络协议

UDP与TCP的区别:

UDP将数据及源和目的封装成数据包,不需要建立链接,每个数据报的大小在现状在64k内,因无连接,所以是不可靠的协议,不需要建立连接,速度快。

TCP建立连接,形成传输数据的通道,在连接中进行大数据量传输,通过三次握手完成连接,是可靠协议,必须建立连接,效率会稍低。

二、UDP协议简单例子与知识点

在UDP协议中,一个通讯路径中有两个端点,一个是接收端,一个是发送端。

发送端:实例化UDP连接的类DatagramSocket(端口号(可选)),封装数据报包DatagramPacket,数据报包相当于邮件包,里面需要封装数据,数据的大小,发送的目的地(ip与端口),最后通过send方法发送数据

接收端:实例化UDP连接DatagramSocket(必填) 此时端口号应该明确说明,因为这样才能让发送端更方便的知道接收方的地址,在接受数据之前,需要准备接收数据的容器,也就是DatagramPacket数据报包,接收数据调用receive()方法接收数据,封装到DatagramPacket包中,调用数据报包的方法,获取发送端的信息与数据,有一个小的知识点在这里提下,就是发送端数据报包的IP地址最后一位为255的话,就能够实现广播的效果,例如:192.168.0.255在这个网段的用户如果存在端口号一致的服务,都能接受到数据的。

例子:从键盘上输入一段文字,通过UDP发送给接收端,接收端,接收到数据显示在控制台上

package com.itheima.net;import java.io.BufferedReader;import java.io.InputStreamReader;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;/** * 网络编程之UDP程序设计 * 模拟网络通讯,发送端发送数据,接收端接收到数据并打印在控制台上 */public class UDPDemo {public static void main(String[] args) throws Exception{//启动程序new Thread(new UDPReceive()).start();new Thread(new UDPSend()).start();}}/** * UDP发送端,把从控制台上接收到的数据发送到接收端 * 发送端实现Runnable接口 *  */class UDPSend implements Runnable{public void run(){send();}//发送数据的方法private void send(){try{//定义UDP发送端DatagramSocket socket = new DatagramSocket();//接收控制台输入的数据,因为我的控制台上UTF-8编码会出现乱码,这里我采用GBK编码BufferedReader mReader = new BufferedReader(new InputStreamReader(System.in,"GBK"));String line = null;while((line = mReader.readLine())!=null){byte[] buf = line.getBytes();//定义要发送的数据包  DatagramPacket p = new DatagramPacket/*发送的数据  数据长度    发送到的地址                                     发送到那个端口*/(buf, 0, buf.length, InetAddress.getByName("127.0.0.1"), 10000);socket.send(p);if(line.equals("bye")){//键盘接收数据不能够停止,所以需要定义一个终止符break;}}System.out.println("发送端结束...");}catch(Exception e){e.printStackTrace();}}}class UDPReceive implements Runnable{public void run(){try{//定义UDP接收端,接收端采用多线程,接收端口号为10000的所有数据DatagramSocket socket = new DatagramSocket(10000);while(true){String result = receive(socket);System.out.println(result);//加上一下代码是为了终止接收端代码...终止接收端是不合理的。if(result!=null && result.equals("bye")){System.out.println("接收端结束...");break;}}}catch(Exception e){e.printStackTrace();}}private String receive(DatagramSocket socket){try{//因为UDP接收数据的最大长度为64k,所以定义一个64K为长度的缓冲区byte[] buf = new byte[64*1024];//定义数据包,接收数据DatagramPacket p = new DatagramPacket(buf, buf.length);socket.receive(p);//获取数据包中的数据byte[] result = p.getData();//得到发送端发送的数据String data = new String(result,0,result.length);System.out.println(p.getAddress().getHostName()+p.getPort()+"说:"+data);if(data.trim().equals("bye")){return "bye";}return null;}catch(Exception e){e.printStackTrace();return null;}}}
三、TCP协议与知识点

Java中使用Socket(套接字)完成TCP程序的开发,使用此类可以方便的建立可靠的、双向的、持续的、点对点的通讯连接

TCP里面有两个重要的类:Socket类与ServerSocket类,ServerSocket类主要用在服务端程序的开发上(服务端一般都是多线程的),用于接收客户端的连接请求,常用的方法:

构造方法:ServerSocket(int port),创建ServerSocket实例,用于监听指定端口

方法:

accept();等待客户端连接,是一个阻塞式方法

getInetAddress();得到IP

close();关闭连接

在服务端每次运行时都会使用accept()方法等待客户端的请求,当有客户端请求过来时,说返回一个Socket对象,该对象就是一个客户端对象,Socket对象常用的方法有:

构造方法:Socket(String host,int port),构造Socket对象,同时指定要连接的服务器主机与端口号

方法:

getInputStream()返回Socket对象的输入流

getOutputStream()返回Socket对象的输出流

close()关闭连接

分析学习下面最简单的TCP程序(这里先使用单线程)

服务端代码

package com.itheima.net;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.net.ServerSocket;import java.net.Socket;/** * 最简单的一个TCP程序,服务端 * 客户端输入一个小写字符,服务端把大写返回 */public class TCPServerDemo1 {public static void main(String[] args) throws Exception{//建立服务端ServerSocket ss = new ServerSocket(10001);//等待客户端请求Socket s = ss.accept();//客户端请求到来,输出客户端信息  主机名System.out.println(s.getInetAddress().getHostName()+"连接到我的服务....");BufferedReader mReader = new BufferedReader(new InputStreamReader(s.getInputStream()));OutputStreamWriter writer = new OutputStreamWriter(s.getOutputStream());String line = null;while((line = mReader.readLine())!=null){//转换为大写发送出去System.out.println("服务端接收到了数据....");writer.write(line.toUpperCase());//写出换行符,表示改行已经结束writer.write(System.getProperty("line.separator"));writer.flush();System.out.println("服务端数据返回。");}//释放资源.....s.close();ss.close();}}

客户端代码

package com.itheima.net;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.net.Socket;/** * TCP程序的客户端 * @author Administrator * */public class TCPClientDemo1 {public static void main(String[] args) throws Exception{//向指定主机,这里是本机的指定端口10001发送请求Socket s = new Socket("127.0.0.1", 10001);//获取键盘输入BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));//获取网络输出流对象,向服务端发送消息OutputStreamWriter out = new OutputStreamWriter(s.getOutputStream());//获取网络输入流对象,获取服务器返回值BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));String line = null;while((line = reader.readLine())!=null){System.out.println(line+"---");out.write(line);//写出换行符,表示改行已经结束//当然这里也可以使用BufferedWriter,里面有newLine()方法很好用//还有就有更简单的方法PrintWriter 构造方法里面有autoFlush这个选项。out.write(System.getProperty("line.separator"));out.flush();System.out.println("客户端发送出了数据");System.out.println("服务端返回的数据是:"+in.readLine());}}}

下面使用多线程的方式完成服务端代码的编写,支持多线程并发访问

需求:完成图片上传,服务器端支持多个客户端并发上传图片

服务端代码:

package com.itheima.net;import java.io.BufferedInputStream;import java.io.OutputStreamWriter;import java.io.PrintStream;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;/** * TCP程序服务端 * 目标:支持多个客户端并发访问 * 技术:Socket、多线程、IO */public class TCPServerDemo2 {public static void main(String[] args) throws Exception{//定义服务端ServerSocket ss = new ServerSocket(10002);//每个客户端进入,都会开辟一个新的线程,处理while(true){//等待客户端连接Socket s = ss.accept();//开启线程new Thread(new Server(s)).start();}}}final class Server implements Runnable{private Socket s;//每个服务端线程,对应一个客户端public Server(Socket s){this.s = s;}@Overridepublic void run() {try{System.out.println(s.getInetAddress().getHostName()+"连接到服务端....");//得到网络输入流,接收客户端数据BufferedInputStream in = new BufferedInputStream(s.getInputStream());//得到文件输出流PrintStream writer = new PrintStream(System.currentTimeMillis()+".jpg");byte[] buf = new byte[1024];int len = -1;while((len = in.read(buf))!=-1){writer.write(buf, 0, len);}writer.close();//得到网络输出流,通知客户端,完成了上传PrintWriter out = new PrintWriter(new OutputStreamWriter(s.getOutputStream()),true);out.println("上传成功!");//下面是释放资源s.close();writer.close();}catch(Exception e){e.printStackTrace();}}}

客户端代码:

package com.itheima.net;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;import java.util.concurrent.TimeUnit;//模拟客户端--第一个public class TCPClientDemo2 {public static void main(String[] args) throws Exception{Socket s = new Socket("127.0.0.1", 10002);//获取网络输入流,接收服务端反馈信息BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));//获取网络输出流PrintStream out = new PrintStream(new BufferedOutputStream(s.getOutputStream()));//获取读取文件流BufferedInputStream reader = new BufferedInputStream(new FileInputStream("a.jpg"));byte[] buf = new byte[1024];int len = -1;while((len = reader.read(buf))!=-1){//模拟大文件TimeUnit.SECONDS.sleep(1);out.write(buf,0,len);out.flush();//晕..我以为资源关闭会自动flush的..测试结果还需要手动flush}//结束标志s.shutdownOutput();reader.close();//服务端返回数据String line = in.readLine();System.out.println("服务端说:"+line);s.close();}}



我在做测试的时候,复制一份客户端启动,模拟多个客户端并发请求服务端...


最后,还有一个知识点需要点出,就是HttpURLConnection,这个类的使用方法在JavaIO里面有个例子,就是模拟多线程下载文件。


总结:

在网络编程开发思路都是一样的,获取服务端连接,发送请求,得到服务端反馈信息。


---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net



0 0
原创粉丝点击