端口:
物理端口:看的见摸得着的接口
逻辑端口:用于标识进程的逻辑地址,不同进程的标识;有效端口:0~65535,其中0~1024系统使用或保留端口。
IP地址:
网络中设备的标识
不易记忆,可用主机名
本地回环地址:127.0.0.1 主机名:locahost
例:获取IP
import java.net.*; class IPDemo { public static void main(String[] args) throws UnknownHostException { //通过名称(ip字符串或主机名)来获取一个ip对象。 InetAddress ip = InetAddress.getByName("www.baidu.com"); System.out.println("addr:"+ip.getHostAddress()); System.out.println("name:"+ip.getHostName()); } }
传输协议:
通讯的规则常用的传输协议:UDP、TCP
UDP:将数据及源和目的封装成数据包,不需要建立连接每个数据报的大小限制在64K内因无连接,是不可靠协议不需要建立连接,速度快
TCP:建立连接,形成传输数据的通道在连接中进行大数据量的传输通过三次握手完成连接,是可靠协议必须建立连接,效率会稍低
Socket:套接字,通信的端点。
就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。
UDP传输:
1,只要是网络传输,必须有socket 。
2,数据一定要封装到数据包中,数据包中包括目的地址、端口、数据等信息。
3,DatagramSocket. 封装了udp传输协议的socket对象。
4,因为数据包中包含的信息较多,为了操作这些信息方便,也一样会将其封装成对象。这个数据包对象就是:DatagramPacket.通过这个对象中的方法,就可以获取到数据包中的各种信息。
DatagramSocket具备发送和接受功能,在进行udp传输时,需要明确一个是发送端,一个是接收端
UDP发送端:
1,建立udp的socket服务,创建对象时如果没有明确端口,系统会自动分配一个未被使用的端口。
2,明确要发送的具体数据。
3,将数据封装成了数据包。
4,用socket服务的send方法将数据包发送出去。
5,关闭资源
import java.net.*; import java.io.*; class udpSend { public static void main(String[] args) throws Exception { //获取IP InetAddress i = InetAddress.getLocalHost(); System.out.println(i.getHostName()); //创建udp对象,通过DatagramSocket对象 DatagramSocket ds = new DatagramSocket(); //确定数据并封装成数据包,DatagramPacket(byte[] buf, int length, InetAddress address, int port); byte[] buf = "udp wo lai le".getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.103"),1000); //通过socket服务,将已有的数据包发出去 ds.send(dp); //关闭资源 ds.close(); } }
UDP接收端:
1,创建udp的socket服务,必须要明确一个端口,作用在于,只有发送到这个端口的数据才是这个接收端可以处理的数据。
2,定义数据包,用于存储接收到数据。
3,通过socket服务的接收方法将收到的数据存储到数据包中。
4,通过数据包的方法获取数据包中的具体数据内容,比如ip、端口、数据等等。
5,关闭资源。
class udpRece { public static void main(String[] args) throws Exception { //创建创建udp对象,通过DatagramSocket对象,建立端点 DatagramSocket ds = new DatagramSocket(1000); //定义数据包,用于接收 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); //通过服务的receive方法将收到的数据存入数据包中 ds.receive(dp); //通过数据包的方法获取其中的数据 String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); int port = dp.getPort(); System.out.println("ip:"+ip+"shuju:"+data+"-"+port); ds.close(); } }
练习:UDP聊天
/* 练习:一个dos窗口,聊天程序 因为是同一个dos命令行在运行一个料条程序,所以是要同时启动两个线程 */ import java.io.*; import java.net.*; //聊天发送端 class Send implements Runnable { private DatagramSocket ds; 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) { if("over".equals(line)) //如果录入over则退出聊天 break; //将键盘录入的内容封装成报包发送到指定端口 byte[] buf = line.getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.253.1"),10002); ds.send(dp); //发送数据报包 } } catch (Exception e) { throw new RuntimeException("上传失败"); } } } //聊天接收端 class Rece implements Runnable { private DatagramSocket ds; 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()); System.out.println(ip+":"+data); } } catch (Exception e) { throw new RuntimeException("读取失败"); } } } class SocketDemo { 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(); //创建接收端线程 } }<strong> </strong>
TCP传输:两个端点的建立连接后会有一个传输数据的通道,这通道称为流,而且是建立在网络基础上的流,称之为socket流。该流中既有读取,也有写入。
tcp的两个端点:一个是客户端,一个是服务端。
客户端:对应的对象,Socket
服务端:对应的对象,ServerSocket
客户端:
1,建立socket服务,指定要连接的主机和端口
2,获取socket流中的输出流,将数据写到该流中,通过网络发送给服务端,
3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印
4,关闭客户端资源
import java.net.*; import java.io.*; class TcpClient { public static void main(String[] args) throws Exception { //建立socket服务,指定要连接的主机和端口 Socket s = new Socket("192.168.1.103",10003); //获取socket流中的输出流,将数据写到该流中,通过网络发送给服务端, OutputStream out = s.getOutputStream(); out.write("服务端,你好".getBytes()); //获取socket流中的输入流,将服务端反馈的数据获取到,并打印 InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); System.out.println(new String(buf,0,len)); //关闭资源 s.close(); } }
服务端:
1,创建服务端socket服务,并监听一个端口。
2,服务端为了给客户端提供服务,获取客户端的内容,可以通过accept方法获取连接过来的客户端对象。
3,可以通过获取到的socket对象中的socket流和具体的客户端进行通讯。
4,如果通讯结束,关闭资源。注意:要先关客户端,再关服务端。
class TcpServer { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(10003); Socket s = ss.accept(); //侦听并接受到此套接字的连接。 //获取此套接字的数据 String ip = s.getInetAddress().getHostAddress(); System.out.print(ip+":"); 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(); out.write("我收到了".getBytes()); //关闭资源 s.close(); ss.close(); } }
练习:TCP多处上传
/* 建立一个服务端,有多个客户端,多个客户端可以同时上传数据 这时,就要用到多线程知识,当接受到一个客户端数据时,将客户端的数据独立开启一个线程 */ import java.io.*; import java.net.*; class TCPClient { public static void main(String[] args) throws Exception //运行:java TCPClient d:\\学生成绩表.txt, { if(args.length!=1) //如果满足条件,则运行主函数时,传递的参数不是所需参数 { System.out.println("请选择一个.txt文件"); return; } File file = new File(args[0]); if(!(file.exists()&&file.isFile())) { System.out.println("文件不存在,不是文件"); return; } Socket s = new Socket("192.168.1.103",10005); FileInputStream fis = new FileInputStream(file); OutputStream os = s.getOutputStream(); byte[] buf = new byte[1024]; int len = 0; while((len=fis.read(buf))!=-1) { os.write(buf,0,len); } //告诉服务器数据已写完 s.shutdownOutput(); fis.close(); //读取服务端反馈回来的信息 InputStream is = s.getInputStream(); byte[] buff = new byte[1024]; int leng = 0; leng = is.read(buff); String message = new String(buff,0,leng); System.out.println(message); } } /* 这个服务端有个局限性,当A客户连接上以后,被服务端获取到,服务端执行具体流程, 这是B客户端连接,只有等待 因为这个服务还没有处理好A客户端的处理请求,还有循环回来执行下次accept方法,所以 暂时获取不到B客户端对象 那么为了可以让多个客户端同时并发的访问本服务端,那么服务端最好就是每个客户端封装到单独的线程张 这样,就可以同时处理多个客户端请求 */ class TCPServer { public static void main(String[] args) throws Exception { //服务端监听端口 ServerSocket ss = new ServerSocket(10005); while(true) { //如果有多个用户同时上传,则获取到每个用户的Socket后,创建一个新的线程 Socket s = ss.accept(); new Thread(new TCPThread(s)).start(); } } } class TCPThread implements Runnable { private Socket s; TCPThread(Socket s) { this.s = s; } public void run() { int count = 1; //获取IP String ip = s.getInetAddress().getHostAddress(); try { //如果一个用户多次上传文件,要避免文件被覆盖 File file = new File("d:\\"+ip+"("+(count)+")"+".txt"); while(file.exists()) file = new File("d:\\"+ip+"("+(count++)+")"+".txt"); FileOutputStream fos = new FileOutputStream(file); //读取客户端发过来的数据并将文件写入指定路径 InputStream is = s.getInputStream(); byte[] buf = new byte[1024]; int len = 0; while((len=is.read(buf))!=-1) { fos.write(buf,0,len); } OutputStream os = s.getOutputStream(); os.write("上传成功".getBytes()); } catch (Exception e) { //throw new RuntimeException("上传失败"); } } }
练习:TCP用户登陆
/* 客户端通过键盘录入用户名 服务端对这个用户进行校验 如果该用户存在,在服务端显示XXX已登陆, 并在客户端显示XXX,欢迎光临 如果该用户不存在,在服务端显示XXX,尝试登陆 并在客户端显示XXX,改用户不存在 最多登陆三次 */ import java.io.*; import java.net.*; class TCPClints1 { public static void main(String[] args) throws Exception //用户端 { Socket s = new Socket("192.168.1.103",10006); BufferedReader bufr = //键盘录入用户名 new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(s.getOutputStream()); //获取网络中的输出流 BufferedReader bufIn = //获取网络中的输入流 new BufferedReader(new InputStreamReader(s.getInputStream())); for (int x = 0; x<3;x++ ) //只允许用户输入三次,三次不对那么跳出循环,不在录入 { String line = bufr.readLine(); out.println(line); String str = bufIn.readLine(); //获取服务端返回来的信息 System.out.println("str:"+str); } } } class TCPServer1 //服务端 { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(10006); while(true) { Socket s = ss.accept(); new Thread(new TCPThread(s)).start(); //创建不同用户访问服务端线程 } } } class TCPThread implements Runnable //服务端多线程,用于多个用于访问服务端 { private Socket s; TCPThread(Socket s) { this.s = s; } public void run() { try { for (int x=0;x<3 ; x++) { BufferedReader bufrd = new BufferedReader(new FileReader("d:\\用户名.txt")); //读取允许登陆的配置用户文件 BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream())); //获取网络中的输入流 PrintWriter pw = new PrintWriter(s.getOutputStream()); //获取网络中的输出流,并且自动刷新 String name = bufr.readLine(); String line = null; boolean flag = false; while((line=bufrd.readLine())!=null) { if(name.equals(line)) //将用户输入的用户名循环比较配置文件,如果有相同的用户名,则标记为true,并跳出循环 { flag = true; break; } } if(flag) { System.out.println(name+",已登陆"); pw.write(name+",欢迎访问"); pw.flush(); break; } else { System.out.println(name+",尝试登陆"); pw.println(name+",用户名不存在"); } } s.close(); } catch (Exception e) { } } }
04-25
04-25
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交