网络编程
1.socket定义
- 旺旺即时通讯工具、QQ、微信、即时通讯大多数都是通过socket网络编程机制实现的,我们想实现网络的通讯,计算机网络编程是一个实现客户端和服务器端通过一个双向链路进行数据交换的复杂的过程,该过程必须经过三块,分别是:客户端、通信链路、服务器端。为了更好的理解该过程,我们可以将该过程比喻成手机和电脑通过USB数据线进行传输数据的过程,客户端相当于手机,数据链路相当于USB数据线,而电脑相当于服务器。
- socket也叫套接字,相当于数据线两端的插头,java socket是实现java网络编程的机制,socket的底层复杂,java socket就是通过java技术提供了一些简单的API可以更简单有效的使用socket开发而无需了解底层机制;其中服务器端的套接字称为serversocket,而客户端的套接字称为socket,每一个socket的地址都是由IP 地址和端口号组成。
2.socket分类
- socket可以分为两种类型:
- 面向连接的socket通信协议(TCP协议)
- 面向无连接的socket的通信协议(UDP协议)
- 基于TCP协议的socket通信过程分为:服务器监听、客户端请求、连接确认
我们的信息需要在网络上通信,我们就需要连接以太网的知识-OSI参考模型。
- OSI(OPen System Interconnect),即开放式互联。一般都叫OSI参考模型,是ISO国际标准组织参与制定的一种网络标准。
- OSI七层参考模型定义了网络互联的七层框架:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
- 每一层实现各自的功能,并完成与相邻层的接口通信。某一层的服务就是该层或者及其下各层的一种能力,它通过接口提供给更高一层。
3.IP地址
- 两台机器(客户端和服务器端)要想实现互联通信,你首先需要知道对方的地址,这个地址就是IP地址,比如http://www.taobao.com其实在底层,就是通过IP地址:端口号/项目名称/网页地址访问到了存放taobao项目的服务器,那么为了方便好记,会将难记的IP地址通过域名解析器转换成好记的域名地址。
- IP地址分为A、B、C、D、E类
- 如果你想小范围访问,一般设为局域网,也叫内网,IP是以网络+地址的组成,如果网段一致地址不同,就说明是同一个局域网络能够实现互联,但是如果想所有用户都能访问就需要用到以太网实现外网。
4.TCP协议传输
案例1:socket客户端给服务器端发信息
-
服务器端
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; /** * 创建TCP协议服务器 * @author Administrator * */ public class LoginServer { public static void main(String[] args) { ServerSocket serverSocket =null; Socket socket = null; InputStream is =null; BufferedReader br = null; try { //创建socket服务器端,参数5000是端口号,端口号只要不和其他的应用程序冲突就可以随意起 //我们是通过IP地址+端口号找到服务器端 serverSocket = new ServerSocket(5000); //使用accept()监听并接收到socket客户端的连接 socket = serverSocket.accept(); //TCP是面向连接的协议,有序,所以通过流得到客户端发送过来的信息 is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String info; while ((info=br.readLine())!=null) { System.out.println("客户端说:"+info); } } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(br!=null) { br.close(); } if(is!=null) { is.close(); } if(socket!=null) { socket.close(); } if(serverSocket!=null) { serverSocket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
-
客户端
import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; /** * 创建TCP协议的客户端 * @author Administrator * */ public class LoginClient { public static void main(String[] args) { Socket socket = null; OutputStream os = null; try { //创建了客户端socket /** * 参数1:需要连接的服务器端的ip地址,我现在是本机的服务器端可以用localhost * 参数2:连接服务器端的端口号,服务器地址由ip地址+端口号组成 */ socket = new Socket("localhost",5000); String info="在吗?"; os = socket.getOutputStream(); os.write(info.getBytes()); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(os!=null) { os.close(); } if(socket!=null) { socket.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
- 操作步骤:先启动服务器端,再启动客户端发送信息给服务器;服务器监听到了客户端发过来的信息后通过输入流得到客户端发过来的信息
案例2:socket服务器端和客户端互相通信
-
服务器端
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /** * 创建TCP协议服务器 * @author Administrator * */ public class LoginServer { public static void main(String[] args) { ServerSocket serverSocket =null; Socket socket = null; InputStream is =null; BufferedReader br = null; OutputStream os = null; try { //创建socket服务器端,参数5000是端口号,端口号只要不和其他的应用程序冲突就可以随意起 //我们是通过IP地址+端口号找到服务器端 serverSocket = new ServerSocket(5000); //使用accept()监听并接收到socket客户端的连接 socket = serverSocket.accept(); //TCP是面向连接的协议,有序,所以通过流得到客户端发送过来的信息 is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String info; while ((info=br.readLine())!=null) { System.out.println("客户端说:"+info); } //半关闭状态,关闭输入流 // socket.shutdownInput(); os = socket.getOutputStream(); String returnInfo = "在"; os.write(returnInfo.getBytes()); } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(os!=null) { os.close(); } if(br!=null) { br.close(); } if(is!=null) { is.close(); } if(socket!=null) { socket.close(); } if(serverSocket!=null) { serverSocket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
-
客户端
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; /** * 创建TCP协议的客户端 * @author Administrator * */ public class LoginClient { public static void main(String[] args) { Socket socket = null; OutputStream os = null; InputStream is =null; BufferedReader br = null; try { //创建了客户端socket /** * 参数1:需要连接的服务器端的ip地址,我现在是本机的服务器端可以用localhost * 参数2:连接服务器端的端口号,服务器地址由ip地址+端口号组成 */ socket = new Socket("localhost",5000); String info="在吗?"; os = socket.getOutputStream(); os.write(info.getBytes()); //关闭输出流,将socket半关闭状态 socket.shutdownOutput(); //创建输入流, is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String returnInfo; while ((returnInfo=br.readLine())!=null) { System.out.println("服务器端说:"+returnInfo); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(br!=null) { br.close(); } if(is!=null) { is.close(); } if(os!=null) { os.close(); } if(socket!=null) { socket.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
案例3客户端发送对象给服务器
-
User类
import java.io.Serializable; public class User implements Serializable{ private static final long serialVersionUID = 114722; private String name; private int age; public User() { super(); } public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
-
服务器端
import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /** * 创建TCP协议服务器 * @author Administrator * */ public class LoginServer { public static void main(String[] args) { ServerSocket serverSocket =null; Socket socket = null; InputStream is =null; ObjectInputStream ois = null; OutputStream os = null; try { //创建socket服务器端,参数5000是端口号,端口号只要不和其他的应用程序冲突就可以随意起 //我们是通过IP地址+端口号找到服务器端 serverSocket = new ServerSocket(5000); //使用accept()监听并接收到socket客户端的连接 socket = serverSocket.accept(); //TCP是面向连接的协议,有序,所以通过流得到客户端发送过来的信息 is = socket.getInputStream(); //在服务器通过ObjectInputStream反序列化 ois = new ObjectInputStream(is); User user = (User)ois.readObject(); System.out.println("姓名:"+user.getName()); System.out.println("年龄:"+user.getAge()); socket.shutdownInput(); os = socket.getOutputStream(); os.write("收到信息".getBytes()); } catch (ClassNotFoundException e) { e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(os!=null) { os.close(); } if(ois!=null) { ois.close(); } if(is!=null) { is.close(); } if(socket!=null) { socket.close(); } if(serverSocket!=null) { serverSocket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
-
客户端
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; /** * 创建TCP协议的客户端 * @author Administrator * */ public class LoginClient { public static void main(String[] args) { Socket socket = null; OutputStream os = null; ObjectOutputStream oos = null; InputStream is =null; BufferedReader br = null; User user = new User("张三",18); try { socket = new Socket("localhost",5000); os = socket.getOutputStream(); oos = new ObjectOutputStream(os); oos.writeObject(user);//将对象写入 oos.flush();//刷新流 //关闭输出流,将socket半关闭状态 socket.shutdownOutput(); //创建输入流, is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String returnInfo; while ((returnInfo=br.readLine())!=null) { System.out.println("服务器端说:"+returnInfo); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(br!=null) { br.close(); } if(is!=null) { is.close(); } if(oos!=null) { oos.close(); } if(os!=null) { os.close(); } if(socket!=null) { socket.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
案例4:通过多线程将多个客户端信息发送给服务端
-
服务器同时接受不同的客户端发送的信息,需要通过多线程实现。
-
服务器端
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * 多线程实现服务端接收多个客户端的信息 * @author Administrator * */ public class LoginServer { public static void main(String[] args) { ServerSocket serverSocket =null; Socket socket = null; try { serverSocket = new ServerSocket(5000); while(true) { //通过循环持续监听客户信息 socket = serverSocket.accept(); LoginThread loginThread = new LoginThread(socket); loginThread.start(); } }catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(socket!=null) { socket.close(); } if(serverSocket!=null) { serverSocket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
-
服务器端线程
import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.net.Socket; public class LoginThread extends Thread{ private Socket socket = null; public LoginThread(Socket socket) { this.socket=socket; } @Override public void run() { InputStream is = null; ObjectInputStream ois = null; OutputStream os = null; try { is = socket.getInputStream(); ois = new ObjectInputStream(is); User user = (User)ois.readObject(); System.out.println("服务器:客户信息:姓名"+user.getName()+"年龄:"+user.getAge()); socket.shutdownInput(); os = socket.getOutputStream(); os.write("收到信息".getBytes()); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }finally { try { if(os!=null) { os.close(); } if(ois!=null) { ois.close(); } if(is!=null) { is.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
-
客户端1
/** * 创建TCP协议的客户端 * @author Administrator * */ public class LoginClient { public static void main(String[] args) { Socket socket = null; OutputStream os = null; ObjectOutputStream oos = null; InputStream is =null; BufferedReader br = null; User user = new User("张三",18); try { socket = new Socket("localhost",5000); os = socket.getOutputStream(); oos = new ObjectOutputStream(os); oos.writeObject(user);//将对象写入 oos.flush();//刷新流 //关闭输出流,将socket半关闭状态 socket.shutdownOutput(); //创建输入流, is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String returnInfo; while ((returnInfo=br.readLine())!=null) { System.out.println("服务器端说:"+returnInfo); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(br!=null) { br.close(); } if(is!=null) { is.close(); } if(oos!=null) { oos.close(); } if(os!=null) { os.close(); } if(socket!=null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
-
客户端2
/** * 创建TCP协议的客户端 * @author Administrator * */ public class LoginClient { public static void main(String[] args) { Socket socket = null; OutputStream os = null; ObjectOutputStream oos = null; InputStream is =null; BufferedReader br = null; User user = new User("李四",20); try { socket = new Socket("localhost",5000); os = socket.getOutputStream(); oos = new ObjectOutputStream(os); oos.writeObject(user);//将对象写入 oos.flush();//刷新流 //关闭输出流,将socket半关闭状态 socket.shutdownOutput(); //创建输入流, is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String returnInfo; while ((returnInfo=br.readLine())!=null) { System.out.println("服务器端说:"+returnInfo); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(br!=null) { br.close(); } if(is!=null) { is.close(); } if(oos!=null) { oos.close(); } if(os!=null) { os.close(); } if(socket!=null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
-
客户端3
/** * 创建TCP协议的客户端 * @author Administrator * */ public class LoginClient { public static void main(String[] args) { Socket socket = null; OutputStream os = null; ObjectOutputStream oos = null; InputStream is =null; BufferedReader br = null; User user = new User("王五",19); try { socket = new Socket("localhost",5000); os = socket.getOutputStream(); oos = new ObjectOutputStream(os); oos.writeObject(user);//将对象写入 oos.flush();//刷新流 //关闭输出流,将socket半关闭状态 socket.shutdownOutput(); //创建输入流, is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String returnInfo; while ((returnInfo=br.readLine())!=null) { System.out.println("服务器端说:"+returnInfo); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭资源 if(br!=null) { br.close(); } if(is!=null) { is.close(); } if(oos!=null) { oos.close(); } if(os!=null) { os.close(); } if(socket!=null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
-
5.UDP协议传输
- UDP叫做无连接传输协议,TCP通过流传输,是以先进先出有序输出,比如ABCDE传输过去后,接收到的也是ABCDE;但是无连接不是,很有可能ABCDE输出得到的是ABCE,这种传输可以用于图片或者音频、视频等文件,传输速度比TCP要快。UDP了解即可。
案例1:客户端给服务器端发信息
-
服务器端
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class LoginServer { public static void main(String[] args) { //准备一个空包 byte[] infos = new byte[1024]; DatagramPacket dp = new DatagramPacket(infos, infos.length); try { //创建socket(快递站) DatagramSocket socket = new DatagramSocket(5000); //接收客户端发来的信息并且装到dp这个包裹里面 socket.receive(dp); //拆包裹,将DatagramPacket里面的数据转换成字符串输出 String info = new String(dp.getData(), 0, dp.getData().length); System.out.println("客户端说:"+info); //关闭资源 socket.close(); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
-
客户端
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; /** * UDP协议传输 客户端 * @author Administrator * */ public class LoginClient { public static void main(String[] args) { String info = "艾玛尼手表"; byte[] infos = info.getBytes(); InetAddress is = null; DatagramPacket dp = null; DatagramSocket socket = null; try { //发送给服务器的IP地址 is = InetAddress.getByName("localhost"); //创建DatagramPacket对象,用于将数据打包,参数是数据、数据的发送IP地址+端口号 dp = new DatagramPacket(infos, infos.length,is,5000); socket = new DatagramSocket(); //通过socket对象将包装了数据的包裹发送到服务器 socket.send(dp); } catch (UnknownHostException e) { e.printStackTrace(); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { //关闭资源 socket.close(); } } }
案例2:服务器端和客户端互相通信
-
服务器端
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress; import java.net.SocketException; public class LoginServer { public static void main(String[] args) { //准备一个空包 byte[] infos = new byte[1024]; DatagramPacket dp = new DatagramPacket(infos, infos.length); try { //创建socket(快递站) DatagramSocket socket = new DatagramSocket(5000); //接收客户端发来的信息并且装到dp这个包裹里面 socket.receive(dp); //拆包裹,将DatagramPacket里面的数据转换成字符串输出 String info = new String(dp.getData(), 0, dp.getData().length); System.out.println("客户端说:"+info); //将信息发回给客户端 //通过接收到的包裹获取客户端的地址 SocketAddress sa = dp.getSocketAddress(); String repalyInfo = "很高兴收到你的礼物,谢谢!"; byte[] repalys = repalyInfo.getBytes(); DatagramPacket dp1 = new DatagramPacket(repalys,0, repalys.length,sa); socket.send(dp1); //关闭资源 if(socket!=null) { socket.close(); } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
-
客户端
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; /** * UDP协议传输 客户端 * @author Administrator * */ public class LoginClient { public static void main(String[] args) { String info = "艾玛尼手表"; byte[] infos = info.getBytes(); InetAddress is = null; DatagramPacket dp = null; DatagramSocket socket = null; try { //发送给服务器的IP地址 is = InetAddress.getByName("localhost"); //创建DatagramPacket对象,用于将数据打包,参数是数据、数据的发送IP地址+端口号 dp = new DatagramPacket(infos, infos.length,is,5000); socket = new DatagramSocket(); //通过socket对象将包装了数据的包裹发送到服务器 socket.send(dp); //准备一个空包 byte[] replays = new byte[1024]; DatagramPacket dp2 = new DatagramPacket(replays, replays.length); socket.receive(dp2); //拆包裹,将DatagramPacket里面的数据转换成字符串输出 String replay = new String(dp2.getData(), 0, dp2.getData().length); System.out.println("服务器说:"+replay); } catch (UnknownHostException e) { e.printStackTrace(); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { //关闭资源 socket.close(); } } }