重要的Socket API:
java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,
. Accept方法用于产生”阻塞”,直到接受到一个连接,并且返回一个客户端的Socket对象实例。”阻塞”是一个术语,它使程序运行暂时”停留”在这个地方,直到一个会话产生,然后程序继续;通常”阻塞”是由循环产生的。
. getInputStream方法获得网络连接输入,同时返回一个InputStream对象实例。
. getOutputStream方法连接的另一端将得到输入,同时返回一个OutputStream对象实例。
注意:其中getInputStream和getOutputStream方法均会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。
InetAddress:
1 import java.net.Inet4Address; 2 import java.net.UnknownHostException; 3 import java.util.Arrays; 4 5 public class InetAddress { 6 7 public static void main(String[] args) throws UnknownHostException{ 8 // 获取本机的InetAddress实例 9 Inet4Address address=(Inet4Address) Inet4Address.getLocalHost(); 10 System.out.println("计算名:"+address.getHostName()); 11 System.out.println("IP地址:"+address.getHostAddress()); 12 byte[] bytes=address.getAddress();//获取字节数组形式的IP地址 13 System.out.println("字节数组形式的IP:"+Arrays.toString(bytes)); 14 System.out.println("直接输出InetAdress对象:"+address);//直接输出InetAdress对象 15 16 //根据机器名获取InetAdress实例 17 Inet4Address address2=(Inet4Address) Inet4Address.getByName("DESKTOP-8J7SNCN"); 18 System.out.println("计算名:"+address2.getHostName()); 19 System.out.println("IP地址:"+address2.getHostAddress()); 20 21 22 //根据IP地址获取InetAdress实例 23 Inet4Address address3=(Inet4Address) Inet4Address.getByName("169.254.38.168"); 24 System.out.println("计算名:"+address3.getHostName()); 25 System.out.println("IP地址:"+address3.getHostAddress()); 26 27 } 28 29 }
url:
1 import java.net.MalformedURLException; 2 import java.net.URL; 3 4 public class Url { 5 public static void main(String[] args) { 6 try{ 7 //创建一个URL实例 8 URL imooc=new URL("http://www.imooc.com"); 9 //?后面表示参数,#后面表示锚点 10 URL url = new URL(imooc,"/index.html?username=tom#test"); 11 System.out.println("协议 :"+ url.getProtocol()); 12 System.out.println("主机 :"+ url.getHost()); 13 //如果未指定端口号,则使用协议默认端口号 14 System.out.println("端口号 :"+ url.getPort()); 15 System.out.println("文件路径 :"+ url.getPath()); 16 System.out.println("文件名称 :"+ url.getFile()); 17 System.out.println("相对路径 :"+ url.getRef()); 18 System.out.println("查询字符串:"+ url.getQuery()); 19 }catch(MalformedURLException e){ 20 e.printStackTrace(); 21 } 22 23 } 24 25 }
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.io.InputStreamReader; 5 import java.net.MalformedURLException; 6 import java.net.URL; 7 8 9 /* 10 * 使用URL读取网页内容 11 */ 12 public class Url2 { 13 public static void main(String[] args) { 14 try { 15 //创建URL实例 16 URL url=new URL("http://www.baidu.com"); 17 //通过URL的openStream方法获取URL对象所表示的资源的字节输入流 18 InputStream is=url.openStream(); 19 //将字节输入流转换为字符输入流 20 InputStreamReader isr=new InputStreamReader(is,"utf-8"); 21 //为字节输入流添加缓冲 22 BufferedReader br=new BufferedReader(isr); 23 String data=br.readLine(); 24 while(data!=null){ 25 System.out.println(data); 26 data=br.readLine(); 27 } 28 br.close(); 29 isr.close(); 30 is.close(); 31 } catch (MalformedURLException e) { 32 e.printStackTrace(); 33 } catch (IOException e) { 34 e.printStackTrace(); 35 } 36 } 37 38 }
重点!!!
通过 Socket 实现 TCP 编程
构造ServerSocket
构造方法:
ServerSocket() ~创建非绑定服务器套接字。
ServerSocket(int port) ~创建绑定到特定端口的服务器套接字。
ServerSocket(int port, int backlog) ~利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(int port, int backlog, InetAddress bindAddr) ~使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
1.1 绑定端口
除了第一个不带参数的构造方法以外, 其他构造方法都会使服务器与特定端口绑定, 该端口有参数 port 指定. 例如, 以下代码创建了一个与 80 端口绑定的服务器:
1 ServerSocket serverSocket = new ServerSocket(80);
1.2 设定客户连接请求队列的长度
当服务器进程运行时, 可能会同时监听到多个客户的连接请求. 例如, 每当一个客户进程执行以下代码:
1 Socket socket = new Socket("www.javathinker.org", 80);
就意味着在远程 www.javathinker.org 主机的 80 端口上, 监听到了一个客户的连接请求.
例子:
服务器端:
1 import java.io.IOException; 2 import java.net.Inet4Address; 3 import java.net.ServerSocket; 4 import java.net.Socket; 5 6 /* 7 * 基于TCP协议的Socket通信,实现用户登陆 8 * 服务器端 9 */ 10 public class Server { 11 12 public static void main(String[] args) { 13 try { 14 // 创建一个服务器端的Socket,即ServerSocket,指定绑定的端口,并监听此端口 15 @SuppressWarnings("resource") 16 ServerSocket serverSocket=new ServerSocket(8888); 17 //记录客户端的数量 18 int count =0 ; 19 System.out.println("***服务器即将启动,等待客户端的连接***"); 20 Socket socket=null; 21 while (true){ 22 //调用accept()方法开始监听,等待客户端的连接 23 socket=serverSocket.accept(); 24 //创建一个新的线程 25 ServerThread serverThread =new ServerThread(socket); 26 //启动线程 27 serverThread.start(); 28 29 count++;//统计客户端的数量 30 System.out.println("客户端的数量"+count); 31 Inet4Address address=(Inet4Address) Inet4Address.getLocalHost(); 32 System.out.println("当前客户端的IP:"+address.getHostAddress()); 33 } 34 35 } catch (IOException e) { 36 // TODO Auto-generated catch block 37 e.printStackTrace(); 38 } 39 40 } 41 42 }
客户端:
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.io.InputStreamReader; 5 import java.io.OutputStream; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 import java.net.UnknownHostException; 9 10 /* 11 * 客户端 12 */ 13 public class Client { 14 public static void main(String[] args) { 15 try { 16 //1.创建客户端Socket,指定服务器地址和端口 17 Socket socket =new Socket("localhost",8888); 18 //2.获取输出流,向服务器发送信息 19 OutputStream os =socket.getOutputStream();//字节输出流 20 PrintWriter pw= new PrintWriter(os);//将输出流包装为打印流 21 pw.write("用户名:admin;密码:123"); 22 pw.flush(); 23 socket.shutdownOutput();//关闭输出流 24 25 //3.获取输入流,并读取服务器端的响应信息 26 InputStream is =socket.getInputStream(); 27 BufferedReader br=new BufferedReader(new InputStreamReader(is)); 28 String info=null; 29 while((info=br.readLine())!=null){ 30 System.out.println("我是客户端,服务器说: "+info); 31 } 32 socket.shutdownInput();//关闭输入流 33 34 //4.关闭资源 35 br.close(); 36 is.close(); 37 pw.close(); 38 os.close(); 39 socket.close(); 40 } catch (UnknownHostException e) { 41 e.printStackTrace(); 42 } catch (IOException e) { 43 e.printStackTrace(); 44 } 45 } 46 }
多线程:
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.io.InputStreamReader; 5 import java.io.OutputStream; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 9 /* 10 * 服务器端线程服处理类 11 */ 12 public class ServerThread extends Thread { 13 //和本线程相关的Socket 14 Socket socket=null; 15 public ServerThread(Socket socket){ 16 this.socket=socket; 17 } 18 //线程执行的操作,响应客户端的请求 19 public void run(){ 20 InputStream is = null; 21 InputStreamReader isr = null; 22 BufferedReader br = null; 23 OutputStream os = null; 24 PrintWriter pw = null; 25 try{ 26 //获取一个输入流,并读取客户端所发送的登陆信息 27 is=socket.getInputStream();//字节输入流 28 isr =new InputStreamReader(is);//将字节流转换为字符流 29 br=new BufferedReader(isr);//为输入流添加缓冲 30 String info=null; 31 while((info=br.readLine())!=null){ 32 System.out.println("我是服务器,客户端说: "+info); 33 } 34 socket.shutdownInput();//关闭输入流 35 36 //获取输入流,响应客户端的请求 37 os=socket.getOutputStream(); 38 pw=new PrintWriter(os); 39 pw.write("欢迎您!"); 40 pw.flush();//调用flush()方法将缓冲输出 41 socket.shutdownOutput();//关闭输出流 42 }catch(IOException e){ 43 e.printStackTrace(); 44 }finally{ 45 //关闭资源 46 try { 47 if(pw!=null){ 48 pw.close(); 49 } 50 if(os!=null){ 51 os.close(); 52 } 53 if(br!=null){ 54 br.close(); 55 } 56 if(isr!=null){ 57 isr.close(); 58 } 59 if(socket!=null){ 60 socket.close(); 61 } 62 } catch (IOException e) { 63 // TODO Auto-generated catch block 64 e.printStackTrace(); 65 } 66 } 67 } 68 69 70 }
通过 Socket 实现 UDP 编程
服务器端:
1 import java.io.IOException; 2 import java.net.DatagramPacket; 3 import java.net.DatagramSocket; 4 import java.net.Inet4Address; 5 6 /* 7 * 服务器端,基于UDP的用户登陆 8 */ 9 public class UDPserver { 10 public static void main(String[] args) throws IOException { 11 //1.创建服务器端DatagramSocket,指定端口 12 DatagramSocket socket = new DatagramSocket(8800); 13 //2.创建数据报,用于接收客户端发送的数据 14 byte[] data =new byte[1024];//创建字节数组,指定接受的数据包的大小 15 DatagramPacket packet=new DatagramPacket(data, data.length); 16 //3.接受客户端发送的数据 17 System.out.println("***服务器已经启动,等待客服端发送数据***"); 18 socket.receive(packet);//此方法在接收到数据报之前会一直阻塞 19 //4.读取数据 20 String info=new String(data,0,packet.getLength()); 21 System.out.println("我是服务器,客户端说"+info); 22 /* 23 * 向服务器端响应数据 24 */ 25 //1定义客户端的地址、端口、数据 26 Inet4Address address=(Inet4Address) packet.getAddress(); 27 int port=packet.getPort(); 28 byte[] data2="欢迎您!".getBytes(); 29 //2.创建数据报,包含响应的数据信息 30 DatagramPacket packet2=new DatagramPacket(data2, data2.length, address,port); 31 //3.响应客户端 32 socket.send(packet2); 33 //4.关闭资源 34 socket.close(); 35 36 37 } 38 }
客户端:
1 import java.io.IOException; 2 import java.net.DatagramPacket; 3 import java.net.DatagramSocket; 4 import java.net.Inet4Address; 5 6 /* 7 * 客户端 8 */ 9 public class UDPclient { 10 public static void main(String[] args) throws IOException { 11 /* 12 * 向服务器端发送数据 13 */ 14 //1.定义服务器的地址、端口号、数据 15 Inet4Address address=(Inet4Address) Inet4Address.getByName("localhost"); 16 int port=8800; 17 byte[] data="用户名“admin;密码123".getBytes(); 18 //2.创建数据报,包发送的数据信息 19 DatagramPacket packet=new DatagramPacket(data, data.length, address,port); 20 //3.创建DatagramPacket对象 21 DatagramSocket socket =new DatagramSocket(); 22 //4.向服务器端发送数据报 23 socket.send(packet); 24 25 /* 26 * 接受服务器端响应的数据 27 */ 28 //1.创建数据报,用于接受服务器端相应的数据 29 byte[] data2=new byte[1024]; 30 DatagramPacket packet2=new DatagramPacket(data2, data2.length); 31 //2.接受服务器相应的数据 32 socket.receive(packet2); 33 //3.读取数据 34 String reply =new String (data2,0,packet2.getLength()); 35 System.out.println("我是客户端,服务器说: "+reply); 36 //4.关闭资源 37 socket.close(); 38 } 39 }
TCP与UDP基本区别
1.基于连接与无连接
2.TCP要求系统资源较多,UDP较少;
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP);
5.TCP保证数据正确性,UDP可能丢包
6.TCP保证数据顺序,UDP不保证
UDP应用场景:
1.面向数据报方式
2.网络数据大多为短消息
3.拥有大量Client
4.对数据安全性无特殊要求
5.网络负担非常重,但对响应速度要求高
具体编程时的区别
1.socket()的参数不同
2.UDP Server不需要调用listen和accept
3.UDP收发数据用sendto/recvfrom函数
4.TCP:地址信息在connect/accept时确定
5.UDP:在sendto/recvfrom函数中每次均 需指定地址信息
6.UDP:shutdown函数无效
基于上述不同,UDP和TCP编程步骤也有些不同,如下:
TCP: TCP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt(); * 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、开启监听,用函数listen();
5、接收客户端上来的连接,用函数accept();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
8、关闭监听;
TCP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置要连接的对方的IP地址和端口等属性;
5、连接服务器,用函数connect();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
UDP:与之对应的UDP编程步骤要简单许多,分别如下:
UDP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、循环接收数据,用函数recvfrom();
5、关闭网络连接;
UDP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置对方的IP地址和端口等属性;
5、发送数据,用函数sendto();
6、关闭网络连接;