------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
一、网络通讯要素:
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();
- }
- }
- }
总结:网络编程具体操作过程特别是涉及到多线程的处理时,相对难理解。TCP部分的示例三、四部分的代码很重要,要理解透彻。