黑马程序员----网络编程

来源:互联网 发布:mac系统被删除了 编辑:程序博客网 时间:2024/05/29 11:42

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


一、网络通讯要素:
IP地址:InetAddress
网络中设备的标识
不易记忆,可用主机名
本地回环地址:127.0.0.1 主机名:localhost
 
端口号
用于标识进程的逻辑地址,不同进程的标识
有效端口:0~65535,其中0~1024系统使用或保留端口

1、InetAddress
public class InetAddress  extends Object  implements Serializable

此类表示互联网协议 (IP) 地址。
IP 地址是 IP 使用的 32 位或 128 位无符号数字,它是一种低级协议,UDP 和 TCP 协议都是在它的基础上构建的。

InetAddress 类提供将主机名解析为其 IP 地址(或反之)的方法。

获取本机计算机名称和IP地址

InetAddress ia = InetAddress.getLocalHost();//getLocalHost是静态方法,直接调用

获取任意主机名称和IP地址

InetAddress i = InetAddress.getByName(String host);
sop(i.getHostAddress());
//sop(i.getHostName());

类似于ping可以直接输入域名,InetAddress也可以这样写:
InetAddress i = InetAddress.getByName("www.baidu.com");//速度相对较慢

反之,如果知道IP地址,也可通过该语句获取主机名称:
InetAddress i = InetAddress.getByName("192.168.0.102");
sop(i.getHostName());

2、Socket

Socket就是为网络服务提供的一种机制。
通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。
3、DatagramSocket 类 

java.net 包中

构造方法: 
   DatagramSocket() //构造数据报套接字并将其绑定到本地主机上任何可用的端口。

常用方法:void send(DatagramPacket p) //从此套接字发送数据报包

4、DatagramPacket 类

java.net 包中

构造方法:
   DatagramPacket(byte[] buf, int length) //构造 DatagramPacket,用来接收长度为 length 的数据包。
   DatagramPacket(byte[] buf, int length, InetAddress address, int port)//构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。 
常用方法:
    int getPort() //返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。  
    InetAddress getAddress() //返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。     
    int getLength() //返回将要发送或接收到的数据的长度。
二、常见协议及示例代码

常见协议:TCP,UDP
UDP的特点:
1.面向无连接
2.数据会被封包.在64K内
3.不可靠,因为无连接.所以不可靠.
4.速度快,因为不需要连接
例如.聊天的时候就是UDP的,还有视频会议,桌面共享等.
TCP的特点:
1.建立连接,形成传输数据的通道.
2.在连接中进行大数据量传输
3.通过三次握手完成连接,是可靠的协议
4.必须建立连接,但是效率稍低
例如,打电话就是TCP的.
UDP就相当于对讲机,TCP相当于电话,
下载就是TCP的因为不能丢数据.聊天就是UDP的

Ⅰ UDP

    实例1:一个简单的UDP发送端程序

import java.net.*;class UdpDemo {public static void main(String[] args) throws Exception{//1.创建UDP服务DatagramSocket ds = new DatagramSocket();//2.确定发送数据byte[] buf = "Hello UDP!".getBytes();//3.封装成包DatagramPacket dp = new DatagramPacket (buf,buf.length,InetAddress.getByName("Datura"),10000);//4.通过send发送ds.send(dp);//关闭资源ds.close();}}
实例2:一个简单的接收端程序
import java.net.*;class UpdReceiveDemo {public static void main(String[] args) throws Exception{//创建数据报套接字并将其绑定到本地主机上的指定端口。DatagramSocket ds = new DatagramSocket(10000);byte[] buf = new byte[1024];//构造 DatagramPacket,用来接收长度为 length 的数据包DatagramPacket dp = new DatagramPacket(buf,buf.length);//调用receive方法:receive(DatagramPacket p) 从此套接字接收数据报包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+":"+port+"]"+data);}}
实例3  聊天程序
/*思路:有收数据的部分,和发数据的部分;这两部分需要同时执行;那就需要用到多线程技术;一个线程控制收,一个线程控制发 因为收和发动作是不一致的,所以要定义两个run方法,而且这两个方法要封装到不同的类中*/import java.io.*;import java.net.*;class ChatDemo {public static void main(String[] args) throws Exception{int sendport=10003;int receport=10007;new Thread(new Send(new DatagramSocket(sendport))).start();new Thread(new Receive(new DatagramSocket(receport))).start();}}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 ("exit".equals(line))break;byte[] buf = line.getBytes();DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("32"),10003);ds.send(dp);}}catch (Exception e){System.out.println("发送失败");}}}class Receive implements Runnable{private DatagramSocket ds;Receive(DatagramSocket ds){this.ds = ds;}public void run(){try{//DatagramSocket ds = new DatagramSocket(10000);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());int port = dp.getPort();System.out.println("["+ip+":"+port+"]"+data);}}catch (Exception e){System.out.println("接受失败");}}}

Ⅱ  TCP

示例一:创建客户端和服务端

/*客户端对应的对象是Socket服务端对应的对象是ServerSocket*/import java.net.*;import java.io.*;class  ClientDemo{public static void main(String[] args) throws Exception{//创建客户端的Socket服务,指定目的主机和端口Socket s = new Socket("192.168.0.102",10006);//为了发送数据,应该获取Socket流中的输出流OutputStream out = s.getOutputStream();out.write("hello TCP".getBytes());s.close();}}class TCPServer {public static void main(String[] args) throws Exception{//建立服务端Socket服务,并监听一个端口ServerSocket ss = new ServerSocket(10006);//通过accept方法获取连接过来的客户端对象Socket s = ss.accept();String ip = s.getInetAddress().getHostAddress();System.out.println(ip+"......is 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();}}
示例二:上传txt文件
import java.io.*;import java.net.*;class  TextClient{public static void main(String[] args) throws Exception{Socket s = new Socket("192.168.1.254",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();}}
示例三:客户并发上传图片:(难点)

/*客户端。1,服务端点。2,读取客户端已有的图片数据。3,通过socket 输出流将数据发给服务端。4,读取服务端反馈信息。5,关闭。*/import java.io.*;import java.net.*;class  PicClient{public static void main(String[] args)throws Exception {if(args.length!=1){System.out.println("请选择一个jpg格式的图片");return ;}File file = new File(args[0]);if(!(file.exists() && file.isFile())){System.out.println("该文件有问题,要么不存在,要么不是文件");return ;}if(!file.getName().endsWith(".jpg")){System.out.println("图片格式错误,请重新选择");return ;}if(file.length()>1024*1024*5){System.out.println("文件过大,请升级权限");return ;}Socket s = new Socket("192.168.1.254",10007);FileInputStream fis = new FileInputStream(file);OutputStream out = s.getOutputStream();byte[] buf = new byte[1024];int len = 0;while((len=fis.read(buf))!=-1){out.write(buf,0,len);}//告诉服务端数据已写完s.shutdownOutput();InputStream in = s.getInputStream();byte[] bufIn = new byte[1024];int num = in.read(bufIn);System.out.println(new String(bufIn,0,num));fis.close();s.close();}}/*服务端这个服务端有个局限性。当A客户端连接上以后。被服务端获取到。服务端执行具体流程。这时B客户端连接,只有等待。因为服务端还没有处理完A客户端的请求,还有循环回来执行下次accept方法。所以暂时获取不到B客户端对象。那么为了可以让多个客户端同时并发访问服务端。那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。如何定义线程呢?只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。*/class PicThread implements Runnable{private Socket s;PicThread(Socket s){this.s = s;}public void run(){int count = 1;String ip  = s.getInetAddress().getHostAddress();try{System.out.println(ip+"....connected");InputStream in = s.getInputStream();File dir =  new File("d:\\pic");File file = new File(dir,ip+"("+(count)+")"+".jpg");while(file.exists())file = new File(dir,ip+"("+(count++)+")"+".jpg");FileOutputStream fos = new FileOutputStream(file);byte[] buf = new byte[1024];int len = 0;while((len=in.read(buf))!=-1){fos.write(buf,0,len);}OutputStream out = s.getOutputStream();out.write("上传成功".getBytes());fos.close();s.close();}catch (Exception e){throw new RuntimeException(ip+"上传失败");}}}class  PicServer{public static void main(String[] args) throws Exception{ServerSocket ss = new ServerSocket(10007);while(true){Socket s = ss.accept();new Thread(new PicThread(s)).start();}//ss.close();}}
示例四:客户并发登陆
/*客户端通过键盘录入用户名。服务端对这个用户名进行校验。如果该用户存在,在服务端显示xxx,已登陆。并在客户端显示 xxx,欢迎光临。如果该用户存在,在服务端显示xxx,尝试登陆。并在客户端显示 xxx,该用户不存在。最多就登录三次。*/import java.io.*;import java.net.*;class  LoginClient{public static void main(String[] args) throws Exception{Socket s = new Socket("192.168.1.254",10008);BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));PrintWriter out = new PrintWriter(s.getOutputStream(),true);BufferedReader bufIn =new BufferedReader(new InputStreamReader(s.getInputStream()));for(int x=0; x<3; x++){String line = bufr.readLine();if(line==null)break;out.println(line);String info = bufIn.readLine();System.out.println("info:"+info);if(info.contains("欢迎"))break;}bufr.close();s.close();}}class UserThread implements Runnable{private Socket s;UserThread(Socket s){this.s = s;}public void run(){String ip = s.getInetAddress().getHostAddress();System.out.println(ip+"....connected");try{for(int x=0; x<3; x++){BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));String name = bufIn.readLine();if(name==null)break;BufferedReader bufr = new BufferedReader(new FileReader("user.txt"));PrintWriter out = new PrintWriter(s.getOutputStream(),true);String line = null;boolean flag = false;while((line=bufr.readLine())!=null){if(line.equals(name)){flag = true;break;}}if(flag){System.out.println(name+",已登录");out.println(name+",欢迎光临");break;}else{System.out.println(name+",尝试登录");out.println(name+",用户名不存在");}}s.close();}catch (Exception e){throw new RuntimeException(ip+"校验失败");}}}class  LoginServer{public static void main(String[] args) throws Exception{ServerSocket ss = new ServerSocket(10008);while(true){Socket s = ss.accept();new Thread(new UserThread(s)).start();}}}



0 0
原创粉丝点击