---------------------- android培训、java培训、期待与您交流! ----------------------
日志完成于11年12月21日
说实话,“网络编程”这一部分知识之前我还真没有系统的学习过,所以对于我,这块知识从头到脚应该都是新的,不过鉴于这学期开了《计算机网络》这门专业课,所以自认为专业课中的理论知识对于我来理解掌握这部分知识应该能起到一定的辅助作用,因为课程之间在思想上还是相通的嘛!呵呵,现在那颗充满强烈的好奇感与求知欲的心又复苏了,那就让我们一起开始今天的学习吧!
1、网络通讯的三要素:
1).找到对方IP地址
2).数据要发送到对方指定的应用程序上。为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识。为了方便称呼这个数字,我们将其称为“端口号”,逻辑端口号。
3).定义通讯规则。这个通讯规则称为传输协议。国际组织定义了通用协议TCP/IP。
2、网络模型
应用层基于传输层,主要协议为HTTP、FTP;传输层的主要协议为TCP、UDP,网际层的主要协议为IP。
范例:获取百度(主机名为:www.baidu.com)的IP地址
import java.net.*; public class IPDemo{ public static void main(String[] args) throws Exception {
//因为百度对应的IP地址为多个,故使用getAllByName(),返回IP 地址所组成的数组 InetAddress[] ia = InetAddress.getAllByName("www.baidu.com"); for(int i=0;i<ia.length;i++){ System.out.println("address:"+ia[i].getHostAddress()); //得到主机地址 System.out.println("name:"+ia[i].getHostName()); //得到主机名称 } } } //百度的IP地址为:119.75.218.77 119.75.217.56 |
3、TCP和UDP(绝对重点)
UDP(用户数据报协议):将数据及源和目的地址封装成数据包,不需要建立连接(即:面向无连接);每个数据报的大小限制在64k内;因无连接,是不可靠协议;不需要连接地址,速度快。 如:网络聊天、网络视频、桌面共享都可以利用UDP传输
TCP(传输控制协议):建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;必须建立连接,效率会稍低。 如:电话通话、下载
Socket(套接字/插座):Socket是为网络服务提供的一种机制;通信的两端都有Socket;网络通信其实就是Socket间的通信;数据在两个Socket间通过IO传输。(可以把Socket理解为码头,由船进行装货卸货来实现码头间数据的传输)。 PS:Socket网络编程主要掌握其流程,代码查文档即可。
4、UDP传输
1).UDP-发送端
要求:通过UDP传输方式,将一段文字数据发送出去。
思路:1,建立updsocket服务。
2,提供数据,并将数据封装到数据包中。
3,通过socket服务的发送功能,将数据包发出去。
4,关闭资源。
import java.net.*; class UdpSend{ public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(8888); //1,创建udp服务,通过DatagramSocket对象。
//2,确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress address, int port); byte[] buf = "udp-发送层".getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("localhost"),10000);
ds.send(dp); //3,通过socket服务,将已有的数据包发送出去,通过send方法。 ds.close(); //4,关闭资源。 } } |
2).UDP-接收端
要求:定义一个应用程序,用于接收udp协议传输的数据并处理的。
思路:1,定义udpsocket服务。通常会监听一个端口,其实就是给这个接收网络应用程序定义数字标识。方便于明确哪些数据过来该应用程序可以处理。
2,定义一个数据包,因为要存储接收到的字节数据。因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3,通过socket服务的receive方法将收到的数据存入已定义好的数据包中。
4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。
5,关闭资源。
import java.net.*; class UdpRece{ public static void main(String[] args) throws Exception{ //1,创建udp socket,建立端点。 DatagramSocket ds = new DatagramSocket(10000); while(true) { //2,定义数据包,用于存储数据。 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); //3,通过服务的receive方法将收到数据存入数据包中。 ds.receive(dp); //阻塞式方法:有数据就接受,没有数据就等 //4,通过数据包的方法获取其中的数据。 String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); int port = dp.getPort(); System.out.println(ip+"::"+data+"::"+port); } //ds.close(); //5,关闭资源
} } |
运行结果如下图所示:先开启接收端,再开启发送端
3).UDP-键盘录入方式发送数据
import java.net.*; import java.io.*;
class UdpSend{ public static void main(String args[]) throws Exception{ DatagramSocket ds=new DatagramSocket(); String line=null; BufferedReader bdfr=new BufferedReader(new InputStreamReader(System.in)); while((line=bdfr.readLine())!=null){ if("886".equals(line)) break; byte[] buf=line.getBytes(); DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("localhost"),10001); ds.send(dp); } ds.close(); } }
class UdpRece{ public static void main(String args[]) throws Exception{ DatagramSocket ds=new DatagramSocket(10001); while(true){ byte[] buf=new byte[1024]; DatagramPacket dp=new DatagramPacket(buf,buf.length); ds.receive(dp);
String ip=dp.getAddress().getHostAddress(); String data=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+"::"+data); }
} } |
运行结果如下图所示:
4).UDP-实现聊天功能
编写一个聊天程序:有接收数据的部分,有发送数据的部分。这两部分需要同时执行,那就需要用到多线程技术。一个线程控制接收,一个线程控制发送。
因为接收和发送动作是不一致的,所以要定义两个run方法。而且这两个方法要封装到不同的类中。
import java.io.*; import java.net.*; class Send implements Runnable { private DatagramSocket ds; public Send(DatagramSocket ds){ this.ds = ds; } public void run(){ try{ BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; while((line=bufr.readLine())!=null){ byte[] buf = line.getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("localhost"),10002); ds.send(dp); if("886".equals(line)) break; } }catch (Exception e){ throw new RuntimeException("发送端失败"); } } }
class Rece implements Runnable{ private DatagramSocket ds; public Rece(DatagramSocket ds){ this.ds = ds; } public void run(){ try{ while(true){ byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); ds.receive(dp); String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); if("886".equals(data)) { System.out.println(ip+"....离开聊天室"); break; } System.out.println(ip+":"+data); } }catch (Exception e){ throw new RuntimeException("接收端失败"); } } }
class ChatDemo{ public static void main(String[] args) throws Exception{ DatagramSocket sendSocket = new DatagramSocket(); DatagramSocket receSocket = new DatagramSocket(10002);
new Thread(new Send(sendSocket)).start(); new Thread(new Rece(receSocket)).start(); } } |
5、TCP传输
1).客户端
在创建Socket对象时,就应该指定目的主机和端口。因为TCP是面向连接的,所以在建立socket服务时,
就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。
要求:给服务端发送给一个文本数据。
步骤:1.创建客户端的socket服务,指定目的主机和端口。
2.获取socket流中的输出流。
3.关闭Socket。
import java.io.*; import java.net.*; class TcpClient { public static void main(String[] args) throws Exception { Socket s = new Socket("localhost",10003); //创建客户端的socket服务,指定目的主机和端口 OutputStream out = s.getOutputStream(); //为了发送数据,应该获取socket流中的输出流。 out.write("TCP 我来了 ".getBytes()); s.close(); } } |
2).服务端
要求:定义端点接收数据并打印在控制台上。
步骤:1,建立服务端的socket服务:ServerSocket(),并监听一个端口。
2,获取连接过来的客户端对象,通过ServerSokcet的accept()。没有连接就会等,所以这个方法阻塞式的。
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。并打印在控制台。
4,关闭服务端。(可选)
import java.io.*; import java.net.*; class TcpServer { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(10003); //建立服务端socket服务,并监听一个端口。 while(true){ Socket s = ss.accept(); //通过accept方法获取连接过来的客户端对象。 String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+".....connected"); //获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。 InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); System.out.println(new String(buf,0,len)); s.close(); //关闭客户端. } //ss.close(); } } |
客户端/服务端
运行结果如下图所示:先启动服务端,再启动客户端
3).TCP传输:客户端和服务端的互访
要求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
客户端: 1,建立socket服务,指定要连接主机和端口。
2,获取socket流中的输出流,将数据写到该流中,通过网络发送给服务端。
3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印。
4,关闭客户端资源。
import java.io.*; import java.net.*;
class TcpClient2 { public static void main(String[] args)throws Exception { Socket s = new Socket("localhost",10004);
OutputStream out = s.getOutputStream(); out.write("服务端,你好".getBytes());
InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); System.out.println(new String(buf,0,len));
s.close(); } }
class TcpServer2{ public static void main(String[] args) throws Exception{ ServerSocket ss = new ServerSocket(10004); Socket s = ss.accept(); String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+"....connected");
InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); System.out.println(new String(buf,0,len));
OutputStream out = s.getOutputStream(); Thread.sleep(10000); out.write("哥们收到,你也好".getBytes()); s.close(); ss.close(); } } |
运行结果如下图所示:
先启动服务器端,再启动客户端
4).TCP练习
要求:建立一个文本转换服务器。
客户端给服务器端发送文本,服务器端将文本转成大写再返回给客户端。而且客户端可以不断的进行文本转换。当客户端输入over时,转换结束。
分析:
客户端:既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。
源:键盘录入。
目的:网络设备,网络输出流。而且操作的是文本数据,可以选择字符流。
步骤
1,建立服务。
2,获取键盘录入。
3,将数据发给服务端。
4,取出服务端返回的大写数据。
5,结束,关资源。
服务端:
源:socket读取流。
目的:socket输出流。
import java.io.*; import java.net.*;
class TransClient{ public static void main(String[] args) throws Exception{ Socket s = new Socket("localhost",10005); //定义读取键盘数据的流对象。 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); //定义目的,将数据写入到socket输出流,发给服务端。 PrintWriter out = new PrintWriter(s.getOutputStream(),true); //定义一个socket读取流,读取服务端返回的大写信息。 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); String line = null; while((line=bufr.readLine())!=null){ if("over".equals(line)) break; out.println(line); String str =bufIn.readLine(); System.out.println("server:"+str); } bufr.close(); s.close(); } }
class TransServer{ public static void main(String[] args) throws Exception{ ServerSocket ss = new ServerSocket(10005); Socket s = ss.accept(); String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+"....connected"); //读取socket读取流中的数据。 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); //目的:socket输出流。将大写数据写入到socket输出流,并发送给客户端。 PrintWriter out = new PrintWriter(s.getOutputStream(),true); String line = null; while((line=bufIn.readLine())!=null){ System.out.println(line); out.println(line.toUpperCase()); } s.close(); ss.close(); } } |
运行结果如下图所示:
6、TCP复制文件
import java.io.*; import java.net.*; class TextClient{ public static void main(String[] args) throws Exception{ Socket s = new Socket("localhost",10006);
BufferedReader bufr = new BufferedReader(new FileReader("IPDemo.java")); PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null; while((line=bufr.readLine())!=null){ out.println(line); } s.shutdownOutput(); //关闭客户端的输出流,相当于给流中加入一个结束标记-1.
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); String str = bufIn.readLine(); System.out.println(str);
bufr.close(); s.close(); } } class TextServer{ public static void main(String[] args) throws Exception{ ServerSocket ss = new ServerSocket(10006); Socket s = ss.accept(); String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+"....connected");
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); PrintWriter out = new PrintWriter(new FileWriter("server.txt"),true);
String line = null; while((line=bufIn.readLine())!=null) { //if("over".equals(line)) //break; out.println(line); }
PrintWriter pw = new PrintWriter(s.getOutputStream(),true); pw.println("上传成功");
out.close(); s.close(); ss.close(); } } |
---------------------- android培训、java培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net/heima