黑马程序员——Java基础之网络编程

来源:互联网 发布:sql sum over 用法 编辑:程序博客网 时间:2024/05/21 11:13

-----------android培训java培训、java学习型技术博客、期待与您交流!------------


Java基础之网络编程

1.网络编程基本概念

         网络编程的本质是两个设备之间通过网络的数据交换,在计算机网络中,设备主要指计算 机。概括的说是把一个设备中的数据发送给另外的一个设备,然后 接受另外一个设备反馈的数据。现在的网络编程基本上都是基于请求/响应方式的,也就是一个设备发送请求数据给另外一个,然后接收另一个设备的反馈。

       在网络编程中,发起连接程序,也就是发送第一次请求的程序,被称作客户端(Client),等待其他程序连接的程序被称作服务器(Server)。客户端程序可以在需要的时候启动,而服务器为了能够时刻相应连接,则需要一直启动。

       例如以打电话为例,首先拨号的人类似于客户端,接听电话的人必须保持电话畅通类似于服务器。连接一旦建立以后,就客户端和服务器端就可以进行数据传递了,而且两者的身份是等价的。在一些程序中,程序既有客户端功能也有服务器端功能,最常见的软件就是 BT、emule 这类软件了。

网络模型(如下图)

    OSI参考模型

   TCP/IP参考模型

2、网络通讯要素

IP地址:

InetAddres:网络中设备的标识,不易记忆,可用主机名;

    本地回环地址:127.0.0.1 主机名:localhost;

端口号:

用于标识进程的逻辑地址,不同进程的标识

    有效端口:0~65535,其中0~1024系统使用或保留端口。

    备注:不是所谓的物理端口!

传输协议:通讯的规则

常见协议:TCP,UDP。

 

3、TCP和UDP的联系和用途

一.区别:

二者都是有用的和常用的,可直接从功能上进行区分,简单明了:

        a.这两种传输协议也就是合于适配不同的业务和不同的硬件终端。在使用中,类似于图像、声音等对可靠性要求没有那么高的业务可以用UDP,他们不 需要准确存储对准确性无要求但要求速度快;类似于文本、程序、文件等要求可靠的数据最好就用TCP,但会牺牲一些速度,对系统资源的要求:CP较多,UDP少。

        b.程序结构:UDP程序结构较简单,TCP复杂。流模式与数据报模式:TCP保证数据正确性,UDP可能丢包;TCP保证数据顺序,UDP不保证。

二.用途

        TCP是面向连接的,有比较高的可靠性,一些要求比较高的服务一般使用这个协议,如FTP、Telnet、SMTP、HTTP、POP3等,而UDP是面向无连接的,使用这个协议的常见服务有DNS、SNMP、QQ等。对于QQ必须另外说明一下,QQ2003 以前是只使用UDP协议的,其服务器使用8000端口,侦听是否有信息传来,客户端使用4000端口,向外发送信息(这也就不难理解在一般的显IP的QQ版本中显示好友的IP地址信息中端口 常为4000或其后续端口的原因了),即QQ程序既接受服务又提供服务,在以后的QQ版本中也支持使用TCP协议了。

Udp是一种面向无连接的通信协议,该协议使得数据传输的速度得到大幅度的提高。视频聊天语音聊天基本都是用UPD协议。

2.网络编主要的类

    网络编程用来的API主要在java.net包中,根据通讯规则不同,可以进行分类如下:


2.UPD通讯规则下的编程

基本步骤:

服务端:

*  建立一个UDP的socket服务,要明一个端口号(此服务会监听这个端品口);

 * 准备一个数据报包对象DatagramPacket,用于封装接收到的数据;

 * 通过socket服务对象的receive(DatagramPacket)方法,接收数据;

 * 处理接收回来的数据(解析DatagramPacket);

 * 关闭资源;

客户端:

* 建立一个UDP的socket服务(可不明确端口号,系统自动配置);

 * 准备数据,并将要发送的数据封装到数据包中(DatagramPacket);

 * 通过socket服务的send(DatagramPacket)方法将数据包发送出去;

 * 关闭资源;

演示代码(简的网络聊天程序):

***********************************************************************//用户一:public class UdpRece {public static void main(String[] args) throws IOException {new Thread(new UdpRece1()).start();//接收端new Thread(new UdpSend1()).start();//发送端}}// 接收信息程序(9080端口)class UdpRece1 implements Runnable {private DatagramSocket ds;UdpRece1() {try {this.ds = new DatagramSocket(9080);} catch (SocketException e) {}}@Overridepublic void run() {System.out.println("用户1接收端开启");String data;// 接收对方接发过来的信息do {byte[] buf = new byte[1024];DatagramPacket dp = new DatagramPacket(buf, buf.length);try {ds.receive(dp);} catch (IOException e) {}String ip = dp.getAddress().getHostAddress();int port = dp.getPort();data = new String(dp.getData(), 0, dp.getData().length);if (data.equals("close")) {break;}System.out.println("---------本次接收到的数据为:-----------");System.out.println(ip);System.out.println(port);System.out.println(data);System.out.println("---------------------------------");} while (true);ds.close();return;}}//发送信息程序class UdpSend1 implements Runnable {private DatagramSocket da;UdpSend1() {try {this.da = new DatagramSocket();} catch (SocketException e) {}}@Overridepublic void run() {System.out.println("用户1发送端开启");do {System.out.println("请输入你要发送的内容(输入'close'退出!):");Scanner scanner = new Scanner(System.in);String ss = scanner.next();if (ss.equals("close")) {break;}// 准备数据,并将数据、要发送的地地址,对方端口号三个信息封装到数据报包对象中byte[] data = ss.getBytes();DatagramPacket dp = null;try {dp = new DatagramPacket(data, data.length,InetAddress.getByName("192.168.1.100"), 9081);} catch (UnknownHostException e) {e.printStackTrace();}// 将数据报包发出去try {da.send(dp);} catch (IOException e) {}} while (true);da.close();return;}}***********************************************************************//用户二public class UdpSend {public static void main(String[] args) throws IOException {new Thread(new UdpRece2()).start();//接收端new Thread(new UdpSend2()).start();//发送端}}//接收信息程序(9080端口)class UdpRece2 implements Runnable {private DatagramSocket ds;UdpRece2() {try {this.ds = new DatagramSocket(9081);} catch (SocketException e) {}}@Overridepublic void run() {System.out.println("用户2接收端开启");String data;// 接收对方接发过来的信息do {byte[] buf = new byte[1024];DatagramPacket dp = new DatagramPacket(buf, buf.length);try {ds.receive(dp);} catch (IOException e) {}String ip = dp.getAddress().getHostAddress();int port = dp.getPort();data = new String(dp.getData(), 0, dp.getData().length);if (data.equals("close")) {break;}System.out.println("---------本次接收到的数据为:-----------");System.out.println(ip);System.out.println(port);System.out.println(data);System.out.println("---------------------------------");} while (true);ds.close();return;}}//发送信息程序:class UdpSend2 implements Runnable {private DatagramSocket da;UdpSend2() {try {this.da = new DatagramSocket();} catch (SocketException e) {}}@Overridepublic void run() {System.out.println("用户2发送端开启");do {System.out.println("请输入你要发送的内容(输入'close'退出!):");Scanner scanner = new Scanner(System.in);String ss = scanner.next();if (ss.equals("close")) {break;}// 准备数据,并将数据、要发送的地地址,对方端口号三个信息封装到数据报包对象中byte[] data = ss.getBytes();DatagramPacket dp = null;try {dp = new DatagramPacket(data, data.length,InetAddress.getByName("192.168.1.100"), 9080);} catch (UnknownHostException e) {e.printStackTrace();}// 将数据报包发出去try {da.send(dp);} catch (IOException e) {}} while (true);da.close();return;}}***********************************************************************

2.TCP通讯规则下的编程

基本步骤:

服务端:

*  1.创建TCP的ServerSocket服务(socket),需要指定监听的端口号;

*  2.通过ServerSocket的accept()方法得到与客户端的socket对象;

 * 3. 通过客户端的socket对象得到连接的输入流InputStream;

*  4.从输入流程中读取客户端发送过来的数据,通过socket对象解析对方发送相关的信息。

*  5.关闭资源;

客户端:

*  1.创建TCP的socket服务(socket),需要对方指定IP地址及端口号;

 * 2.拿到socket输出流OutputStream;

 * 3.通过这个流程将数据写出去;

 * 4.关闭资源;

演示代码:

***********************************************************************//服务端(接收端)public class Tcp_Rece {public static void main(String[] args) throws IOException {//创建ServerSocket服务ServerSocket serverSocket = new ServerSocket(10086);//监听端口,得到客户端的Socket对象Socket socket = serverSocket.accept();//从客户端的Socket对象中得到输入流InputStream in = socket.getInputStream();//从输入流是读取数据int len;byte[] bfu = new byte[1024];while ((len = in.read(bfu)) != -1) {System.out.println(new String(bfu, 0, len));}System.out.println("接收成功");//关闭资源socket.close();serverSocket.close();}}//发送端(客户端)public class Tcp_Send {public static void main(String[] args) throws UnknownHostException,IOException {// 建议服务Socket socket = new Socket("192.168.1.100", 10086);// 得到输出流OutputStreamOutputStream outs = socket.getOutputStream();// 输出数据outs.write("Tcp测试数据".getBytes());System.out.println("发送成功");//关闭资源socket.close();}}***********************************************************************以上代码可以利用多线程的技术进行重构,实现简单的即时聊天程序,由于实现思路与以述UDP的聊天程序基本一致,代码略去。小案例:利用TCP协议编写一个写小转大写的客户端/服务端的网络程序,具体代码如下:***********************************************************************/* * 服务端 *  * */public class Service {public static void main(String[] args) throws IOException {System.out.println("服务端开启");// 创建一个ServerSocket的服务端,监听一个端口ServerSocket ss = new ServerSocket(10086);// 得到客户端的SocketSocket sk = ss.accept();// 从客户端的Socket中得到输入流InputSourceInputStream in = sk.getInputStream();// 从客户端的Socket中得到输出流OutputStreamOutputStream out = sk.getOutputStream();while (true) {// 从InputSource中得到客户端发过来的数据int len;byte[] bfu = new byte[1024];while ((len = in.read(bfu)) != -1) {// 如果客输入的是close,则退出if (bfu.toString().equals("close")) {ss.close();break;}// 将数据转化为大写的byte[] data = new String(bfu, 0, len).toUpperCase().getBytes();// 通过OutputStream将数据输出给客户端out.write(new String("转换结果为:").getBytes());out.write(data, 0, data.length);System.out.println("转换结果为:" + new String(data, 0, data.length));}}// 关闭资源(实际情况下服务端是一直处于开启状态的)// sk.close();}}/* * 客户端 *  * */public class Consumer {public static void main(String[] args) throws IOException {System.out.println("客户端开启");// 创建Socket的服务端Socket sk = new Socket("192.168.1.100", 10086);// 从服务中得到输出流OutputStreamOutputStream out = sk.getOutputStream();// 从服务中得到输入流InputSourceInputStream in = sk.getInputStream();// 从控制台输入数据Scanner scanner = new Scanner(System.in);while (true) {System.out.println("输入你要转换的字母:");String data = scanner.next();// 如果输入的是close就退出if (data.equals("close")) {break;}// 用输出流将数据写到服务端out.write(data.getBytes());// 从输入流中得到服务端的响应信息byte[] bfu = new byte[1024];in.read(bfu);// 将信息显示在控制台上System.out.println(new String(bfu, 0, bfu.length));System.out.println("-----接收成功------");}sk.close();}}***********************************************************************














0 0
原创粉丝点击