1、网络编程基本概念

(1)什么是计算机网络

把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息, 共享硬件、 软件、 数据信息等资源。

(2)计算机网络的主要功能

资源共享
信息传输与集中处理
均衡负荷与分布处理
综合信息服务(www/综合业务数字网络ISDN)等

(3)网络通信协议

要使计算机连成的网络能够互通信息, 需要对数据传输速率、 传输代码、 代码结构、 传输控制步骤、 出错控制等制定一组标准, 这一组共同遵守的通信标准就是网络通信协议, 不同的计算机之间必须使用相同的通讯协议才能进行通信。

网络通信接口:
为了使两个结点之间能进行对话, 必须在它们之间建立通信工具(即接口), 使彼此之间能进行信息交换。 接口包括两部分:
(1) 硬件装置: 实现结点之间的信息传送
(2) 软件装置: 规定双方进行通信的约定协议

(4)TCP/IP

TCP/IP: 传输控制协议/因特网互联协议, 又叫网络通讯协议, 这个协议是Internet最基本的协议、 Internet国际互联网络的基础, 简单地说, 就是由网络层的IP协议和传输层的TCP协议组成的。

IP地址: 网络中每台计算机的一个标识号, 本地IP: 127.0.0.1 localhost

端口号(PORT): 端口号的范围: 0~65535之间, 0~1023之间的端口数是用于一些知名的网络服务和应用

应用层
表示层
会话层
传输层
网络层
数据链接层
物理层

(5)程序开发结构

网络编程主要是指完成C/S程序的开发, 程序的开发结构有两种:
C/S(客户端/服务器)
开发两套程序, 两套程序需要同时维护, 例如: QQ。 CS程序一般比较稳定

B/S(浏览器/服务器)
开发一套程序, 客户端使用浏览器进行访问, 例如: 各个论坛。 BS程序一般稳定性较差, 而且安全性较差。

但是, C/S的程序开发在实际的Java应用中毕竟很少了, 而且整个java基本上都是以B/S为主。

C/S程序主要可以完成以下两种程序的开发:
TCP: (Transmission Control Protocol) 传输控制协议, 采用三方握手的方式, 保证准确的连接操作。
UDP: (User Datagram Protocol) 数据报协议, 发送数据报, 例如: 手机短信或者是QQ消息。
TCP、 UDP的数据帧格式简单图例:

协议类型 源IP 目标IP 源端口 目标端口 帧序号 帧数据

其中协议类型用于区分TCP、 UDP


2、网络编程TCP协议

(1)TCP程序概述

TCP是一个可靠的协议, 面向连接的协议。

实现TCP程序, 需要编写服务器端和客户端, Java API为我们提供了java.net 包, 为实现网络应用程序提供类。

ServerSocket : 此类实现服务器套接字。
Socket : 此类实现客户端套接字(也可以就叫“ 套接字” )。

Socket是网络驱动层提供给应用程序编程的接口和一种机制。

11、网络编程 - 图1

11、网络编程 - 图2

11、网络编程 - 图3

(2)实现服务器端与客户端程序

服务器端:

public class ServerSocket extends Object
此类实现服务器套接字。 服务器套接字等待请求通过网络传入。 它基于该请求执行某些操作, 然后可能向请求者返回结果。

ServerSocket(int port)
创建绑定到特定端口的服务器套接字。

void setSoTimeout(int timeout)
通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。

InetAddress getInetAddress()
返回此服务器套接字的本地地址。

Socket accept()
侦听并接受到此套接字的连接

客户端:
public class Socket extends Object
此类实现客户端套接字(也可以就叫“ 套接字” ) 。 套接字是两台机器间通信的端点。

Socket(String host, int port)
创建一个流套接字并将其连接到指定主机上的指定端口号。

InputStream getInputStream()
返回此套接字的输入流。

OutputStream getOutputStream()
返回此套接字的输出流。

void setSoTimeout(int timeout)
启用/禁用带有指定超时值的SO_TIMEOUT, 以毫秒为单位。


3、TCP 实现ECHO程序

Echo, 意为应答, 程序的功能是客户端向服务器发送一个字符串, 服务器不做任何处理, 直接把字符串返回给客户端, Echo程序是最为基本的客户/服务器程序。

EchoServerDemo

  1. package com.vince;
  2. import java.io.*;
  3. import java.net.ServerSocket;
  4. import java.net.Socket;
  5. /**
  6. */
  7. public class EchoServerDemo {
  8. public static void main(String[] args) {
  9. //创建一个服务器端的Socket(1024-65535)
  10. try {
  11. ServerSocket server = new ServerSocket(6666);
  12. System.out.println("服务器已启动,正在等待客户端的连接...");
  13. //等待客户端的连接,造成阻塞,如果有客户端连接成功,立即返回一个Socket对象
  14. Socket socket = server.accept();
  15. System.out.println("客户端连接成功:"+server.getInetAddress().getHostAddress());
  16. BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  17. //通过输入流读取网络数据,如果没有数据,那么会阻塞
  18. String info = br.readLine();
  19. System.out.println(info);
  20. //获取输出流,向客户端返回消息
  21. PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
  22. ps.println("echo:"+info);
  23. ps.flush();
  24. //关闭
  25. ps.close();
  26. br.close();
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }

EchoClientDemo

  1. package com.vince;
  2. import java.io.*;
  3. import java.net.Socket;
  4. /**
  5. */
  6. public class EchoClientDemo {
  7. public static void main(String[] args) {
  8. //创建一个Socket对象,指定要连接的服务器
  9. try {
  10. Socket socket = new Socket("localhost",6666);
  11. //获取socket的输入输出流
  12. PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
  13. BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  14. ps.println("hello,my name is Bin");
  15. ps.flush();
  16. //读取服务器端返回的数据
  17. String info = br.readLine();
  18. System.out.println(info);
  19. ps.close();
  20. br.close();
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }

11、网络编程 - 图4

11、网络编程 - 图5


4、服务器与多客户端通信

目前为止我们编写的程序中, 服务器只能同时处理一个客户端连接, 要想服务器同时支持多个客户端的连接, 就必须加入多线程的处理机制, 将每一个连接的客户端都创建一个新的线程对象。

MutilServerDemo

  1. package com.vince;
  2. import java.io.*;
  3. import java.net.ServerSocket;
  4. import java.net.Socket;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. /**
  8. * 处理多个客户端
  9. * 主线程用于监听客户端的连接,每次有连接成功,开启一个线程来处理该客户端的消息
  10. */
  11. public class MutilServerDemo {
  12. public static void main(String[] args) {
  13. ExecutorService es = Executors.newFixedThreadPool(3);
  14. try {
  15. ServerSocket server = new ServerSocket(6666);
  16. System.out.println("服务器已启动,正在等待连接。。。");
  17. while(true){
  18. Socket s = server.accept();
  19. System.out.println(s.getInetAddress().getHostAddress());
  20. es.execute(new UserThread(s));
  21. }
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }
  27. /**
  28. * 用来处理客户端请求的线程任务
  29. */
  30. class UserThread implements Runnable{
  31. private Socket s;
  32. public UserThread(Socket s){
  33. this.s = s;
  34. }
  35. @Override
  36. public void run() {
  37. try {
  38. BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
  39. PrintStream ps= new PrintStream(new BufferedOutputStream(s.getOutputStream()));
  40. String info = br.readLine();
  41. System.out.println(info);
  42. ps.println("echo:"+info);
  43. ps.flush();
  44. ps.close();
  45. br.close();
  46. } catch (IOException e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. }

MutilClientDemo

  1. package com.vince;
  2. import java.io.*;
  3. import java.net.Socket;
  4. import java.util.Scanner;
  5. /**
  6. * Created by vince on 2017/6/6.
  7. *
  8. */
  9. public class MutilClientDemo {
  10. public static void main(String[] args) {
  11. Scanner input = new Scanner(System.in);
  12. //创建一个Socket对象,指定要连接的服务器
  13. try {
  14. Socket socket = new Socket("localhost",6666);
  15. //获取socket的输入输出流
  16. PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
  17. BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  18. System.out.println("请输入:");
  19. String info = input.nextLine();
  20. ps.println(info);
  21. ps.flush();
  22. //读取服务器端返回的数据
  23. info = br.readLine();
  24. System.out.println(info);
  25. ps.close();
  26. br.close();
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }

5、多客户端之间的通信

服务器可以与多个客户端实现通信了, 那我们真正的目的是要实现多个客户端之间的通信, 使用TCP协议实现的方案是:
客户端的数据包通过服务器中转, 发送到另一个客户端, 如下图所示:

11、网络编程 - 图6

Message

  1. package com.vince.communication;
  2. import java.io.Serializable;
  3. /**
  4. * 消息包
  5. */
  6. public class Message implements Serializable{
  7. private String from;//发送者
  8. private String to;//接收者
  9. private int type;//消息类型
  10. private String info;//消息
  11. public String getFrom() {
  12. return from;
  13. }
  14. public void setFrom(String from) {
  15. this.from = from;
  16. }
  17. public String getTo() {
  18. return to;
  19. }
  20. public void setTo(String to) {
  21. this.to = to;
  22. }
  23. public int getType() {
  24. return type;
  25. }
  26. public void setType(int type) {
  27. this.type = type;
  28. }
  29. public String getInfo() {
  30. return info;
  31. }
  32. public void setInfo(String info) {
  33. this.info = info;
  34. }
  35. public Message() {
  36. }
  37. public Message(String from, String to, int type, String info) {
  38. this.from = from;
  39. this.to = to;
  40. this.type = type;
  41. this.info = info;
  42. }
  43. @Override
  44. public String toString() {
  45. return "Message{" +
  46. "from='" + from + '\'' +
  47. ", to='" + to + '\'' +
  48. ", type=" + type +
  49. ", info='" + info + '\'' +
  50. '}';
  51. }
  52. }

MassageType

  1. package com.vince.communication;
  2. /**
  3. */
  4. public final class MessageType {
  5. public static final int TYPE_LOGIN = 0x1;//登录消息类型
  6. public static final int TYPE_SEND = 0x2;//发送消息的类型
  7. }

Server

  1. package com.vince.communication;
  2. import javax.security.sasl.SaslClient;
  3. import java.io.IOException;
  4. import java.io.ObjectInputStream;
  5. import java.io.ObjectOutput;
  6. import java.io.ObjectOutputStream;
  7. import java.net.ServerSocket;
  8. import java.net.Socket;
  9. import java.util.Vector;
  10. import java.util.concurrent.ExecutorService;
  11. import java.util.concurrent.Executors;
  12. /**
  13. * 服务器端
  14. */
  15. public class Server {
  16. public static void main(String[] args) {
  17. //保存客户端处理的线程
  18. Vector<UserThread> vector = new Vector<>();
  19. ExecutorService es = Executors.newFixedThreadPool(5);
  20. //创建服务器端的Socket
  21. try {
  22. ServerSocket server = new ServerSocket(8888);
  23. System.out.println("服务器已启动,正在等待连接...");
  24. while(true){
  25. Socket socket = server.accept();
  26. UserThread user = new UserThread(socket,vector);
  27. es.execute(user);
  28. }
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }
  34. /**
  35. * 客户端处理的线程
  36. */
  37. class UserThread implements Runnable{
  38. private String name;//客户端的用户名称(唯一)
  39. private Socket socket;
  40. private Vector<UserThread> vector;//客户端处理线程的集合
  41. private ObjectInputStream ois;
  42. private ObjectOutputStream oos;
  43. private boolean flag = true;
  44. public UserThread(Socket socket,Vector<UserThread> vector){
  45. this.socket = socket;
  46. this.vector = vector;
  47. vector.add(this);
  48. }
  49. @Override
  50. public void run() {
  51. try{
  52. System.out.println("客户端"+socket.getInetAddress().getHostAddress()+"已连接");
  53. ois = new ObjectInputStream(socket.getInputStream());
  54. oos = new ObjectOutputStream(socket.getOutputStream());
  55. while (flag){
  56. //读取消息对象
  57. Message msg = (Message)ois.readObject();
  58. int type = msg.getType();
  59. switch (type){
  60. case MessageType.TYPE_SEND:
  61. String to = msg.getTo();
  62. UserThread ut;
  63. int size = vector.size();
  64. for (int i = 0; i < size; i++) {
  65. ut = vector.get(i);
  66. if (to.equals(ut.name) && ut!=this){
  67. ut.oos.writeObject(msg);
  68. break;
  69. }
  70. }
  71. break;
  72. case MessageType.TYPE_LOGIN:
  73. name = msg.getFrom();
  74. msg.setInfo("欢迎你:");
  75. oos.writeObject(msg);
  76. break;
  77. }
  78. }
  79. ois.close();
  80. oos.close();
  81. }catch (IOException | ClassNotFoundException e){
  82. e.printStackTrace();
  83. }
  84. }
  85. }

Client

  1. package com.vince.communication;
  2. import java.io.IOException;
  3. import java.io.ObjectInputStream;
  4. import java.io.ObjectOutputStream;
  5. import java.net.Socket;
  6. import java.util.Scanner;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. /**
  10. */
  11. public class Client {
  12. public static void main(String[] args) {
  13. Scanner input = new Scanner(System.in);
  14. ExecutorService es = Executors.newSingleThreadExecutor();
  15. try {
  16. Socket socket = new Socket("localhost", 8888);
  17. System.out.println("服务器连接成功");
  18. ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
  19. ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
  20. //向服务器发送登录信息
  21. System.out.println("请输入名称:");
  22. String name = input.nextLine();
  23. Message msg = new Message(name, null, MessageType.TYPE_LOGIN, null);
  24. oos.writeObject(msg);
  25. msg = (Message) ois.readObject();
  26. System.out.println(msg.getInfo() + msg.getFrom());
  27. //启动读取消息的线程
  28. es.execute(new ReadInfoThread(ois));
  29. //使用主线程来实现发送消息
  30. boolean flag = true;
  31. while(flag){
  32. msg = new Message();
  33. System.out.println("To:");
  34. msg.setTo(input.nextLine());
  35. msg.setFrom(name);
  36. msg.setType(MessageType.TYPE_SEND);
  37. System.out.println("Info:");
  38. msg.setInfo(input.nextLine());
  39. oos.writeObject(msg);
  40. }
  41. } catch (IOException | ClassNotFoundException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. }
  46. //读取消息
  47. class ReadInfoThread implements Runnable {
  48. private ObjectInputStream in;
  49. public ReadInfoThread(ObjectInputStream in){
  50. this.in = in;
  51. }
  52. private boolean flag = true;
  53. public void setFlag(boolean flag) {
  54. this.flag = flag;
  55. }
  56. @Override
  57. public void run() {
  58. try {
  59. while (flag) {
  60. Message message = (Message) in.readObject();
  61. System.out.println("[" + message.getFrom() + "]对我说:" + message.getInfo());
  62. }
  63. if(in!=null){
  64. in.close();
  65. }
  66. } catch (IOException | ClassNotFoundException e) {
  67. e.printStackTrace();
  68. }
  69. }
  70. }

6、网络编程UDP协议

(1) UDP协议概述

UDP是User Datagram Protocol的简称, 是一种无连接的协议, 每个数据报都是一个独立的信息, 包括完整的源地址或目的地址, 它在网络上以任何可能的路径传往目的地, 因此能否到达目的地, 到达目的地的时间以及内容的正确性都是不能被保证的, 每个被传输的数据报必须限定在64KB之内。

主要使用以下的两个类:
DatagramPacket: 此类表示数据报包。
DatagramSocket: 此类表示用来发送和接收数据报包的套接字

(2)UDP服务器与客户端程序

服务器端:

  1. String info = “….”
  2. // 将信息封装成数据报
  3. byte[] bytes = info.getBytes();
  4. DatagramPacket dp = new DatagramPacket(bytes, 0, bytes.length(), InetAddress.getByName("localhost"), 5000);// 客户端在5000端口监听
  5. DatagramSocket server = new DatagramSocket(3000);// 服务器的端口
  6. server.send(dp);// 发送数据报
  7. server.close();

客户端:

  1. byte b[] = new byte[1024];// 接收内容
  2. DatagramPacket dp = new DatagramPacket(b, b.length);// 接收内容
  3. // 客户端在5000端口等待
  4. DatagramSocket client = new DatagramSocket(5000);
  5. client.receive(dp); // 接收内容
  6. System.out.println(new String(dp.getData(), 0, dp.getLength()));
  7. client.close();

UDPClientDemo先启动,准备接受数据后,再启动UDPServerDemo发送数据

否则会造成阻塞

UDPServerDemo

  1. package com.vince;
  2. import com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector;
  3. import java.io.IOException;
  4. import java.net.*;
  5. /**
  6. */
  7. public class UDPServerDemo {
  8. public static void main(String[] args) {
  9. String info = "good good 学习,天天 UP";
  10. byte[] bytes = info.getBytes();
  11. try {
  12. //封装一个数据报包
  13. /*
  14. buf - 数据包数据。
  15. offset - 分组数据偏移量。
  16. length - 分组数据长度。
  17. address - 目的地址。
  18. port - 目的端口号。
  19. */
  20. DatagramPacket dp = new DatagramPacket(
  21. bytes,
  22. 0,
  23. bytes.length,
  24. InetAddress.getByName("127.0.0.1"),
  25. 8000);
  26. //本程序的端口
  27. DatagramSocket socket = new DatagramSocket(9000);
  28. socket.send(dp);
  29. socket.close();
  30. }catch (UnknownHostException|SocketException e){
  31. e.printStackTrace();
  32. } catch (IOException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. }

UDPClientDemo

  1. package com.vince;
  2. import java.io.IOException;
  3. import java.net.DatagramPacket;
  4. import java.net.DatagramSocket;
  5. import java.net.SocketException;
  6. /**
  7. * Created by vince on 2017/6/7.
  8. * 客户端
  9. */
  10. public class UDPClientDemo {
  11. public static void main(String[] args) {
  12. byte[] bytes = new byte[1024];
  13. DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
  14. try {
  15. DatagramSocket socket = new DatagramSocket(8000);
  16. System.out.println("正在接收数据中...");
  17. socket.receive(dp);//接收数据
  18. String s = new String(dp.getData(),0,dp.getLength());
  19. System.out.println(s);
  20. socket.close();
  21. } catch (SocketException e) {
  22. e.printStackTrace();
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }

7、URL

(1)URL概述

URL(uniform resource location )类 URL 代表一个统一资源定位符, 它是指向互联网“ 资源” 的指针。

抽象类 URLConnection 是所有类的超类, 它代表应用程序和 URL 之间的通信链接

URLDemo

根据提供的URL下载图片资源,并保存到D盘,保存不到C盘。中间使用文件流进行操作。

  1. package com.vince;
  2. import java.io.BufferedInputStream;
  3. import java.io.BufferedOutputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.net.HttpURLConnection;
  7. import java.net.MalformedURLException;
  8. import java.net.URL;
  9. /**
  10. */
  11. public class URLDemo {
  12. public static void main(String[] args) {
  13. //URL 统一资源定位符
  14. try {
  15. URL url=new URL("https://b.zhutix.com/bizhi/win11-wp/01.jpg");
  16. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  17. BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
  18. BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("D:\\weiruan.jpg"));
  19. byte[] bytes = new byte[1024];
  20. int len =-1;
  21. while((len=in.read(bytes))!=-1){
  22. out.write(bytes,0,len);
  23. out.flush();
  24. }
  25. in.close();
  26. out.close();
  27. System.out.println("下载成功");
  28. } catch (MalformedURLException e) {
  29. e.printStackTrace();
  30. } catch (IOException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }

8、MINA框架

1、 什么是MINA? 一句话就是: 一个简洁易用的基于 TCP/IP 通信的 JAVA框架。

2、 下载地址: MINA Downloads — Apache MINA

3、 一个简单的网络程序需要的最少jar包: mina-core-2.1.3.jar、 slf4j-api-1.7.26.jar

4、 开发一个 Mina 应用, 简单的说, 就是创建连接, 设定过滤规则, 编写自己的消息处理器

5、 示例:

  1. //创建一个非阻塞的Server端Socket,用NIO
  2. SocketAcceptor acceptor = new NioSocketAcceptor(); //创建接收数据的过滤器
  3. DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
  4. //设定这个过滤器将一行一行(/r/n)的读取数据
  5. chain.addLast("myChin", new ProtocolCodecFilter(new TextLineCodecFactory()));
  6. //设定服务器端的消息处理器:一个SampleMinaServerHandler对象
  7. acceptor.setHandler(new SampleMinaServerHandler());
  8. int bindPort = 9999;
  9. //绑定端口,启动服务器
  10. try {acceptor.bind(new InetSocketAddress(bindPort)); } catch (IOException e) {e.printStackTrace();}
  11. System.out.println("Mina Server is Listing on:= " + bindPort);
  1. public class SampleMinaServerHandler extends IoHandlerAdapter{
  2. public void sessionOpened(IoSession session) throws Exception {
  3. super.sessionOpened(session);
  4. System.out.println("incomming client : "+session.getRemoteAddress());
  5. }
  6. public void sessionClosed(IoSession session) throws Exception {
  7. super.sessionClosed(session);
  8. System.out.println("one Clinet Disconnect !");
  9. }
  10. public void messageReceived(IoSession session, Object message) throws Exception {
  11. //我们己设定了服务器解析消息的规则是一行一行读取,这里就可转为String:
  12. String s=(String)message;
  13. System.out.println("收到客户机发来的消息: "+s);
  14. session.write("echo:"+s);
  15. }
  16. }

1、 使用telnet测试: telnet localhost 9999
2、 编写客户端:

  1. NioSocketConnector connector = new NioSocketConnector(); // 创建接收数据的过滤器
  2. DefaultIoFilterChainBuilder chain = connector.getFilterChain();
  3. //设定这个过滤器将一行一行(/r/n)的读取数据
  4. chain.addLast("myChin", new ProtocolCodecFilter(new TextLineCodecFactory()));
  5. //设定服务器端的消息处理器:一个 SamplMinaServerHandler 对象
  6. connector.setHandler(new SampleMinaClientHandler());
  7. connector.setConnectTimeout(30);// Set connect timeout.
  8. //连接到服务器:
  9. ConnectFuture cf = connector.connect(new InetSocketAddress("localhost", 9999));
  10. // Wait for the connection attempt to be finished.
  11. cf.awaitUninterruptibly();
  12. //发送消息
  13. //cf.getSession().getCloseFuture().awaitUninterruptibly();
  14. //connector.dispose();
  1. public class SampleMinaClientHandler extends IoHandlerAdapter {
  2. //当一个客端端连结进入时
  3. public void sessionOpened(IoSession session) throws Exception {
  4. System.out.println("incomming client :"+session.getRemoteAddress()); session.write("我来啦........");
  5. }
  6. //当一个客户端关闭时
  7. public void sessionClosed(IoSession session) {
  8. System.out.println("one Clinet Disconnect !");
  9. }
  10. //当客户端发送的消息到达时:
  11. public void messageReceived(IoSession session, Object message)throws Exception {
  12. //我们己设定了服务器解析消息的规则是一行一行读取,这里就可转为 String:
  13. String s=(String)message;
  14. System.out.println("服务器发来的收到消息: "+s);
  15. //测试将消息回送给客户端
  16. session.write(s);
  17. }
  18. }

使用 Mina 直接传送对象
1、 public class Userinfo implements java.io.Serializable
2、 服务器, 客户端都设定以对象为单位

  1. //设定这个过滤器将以对象为单位读取数据
  2. ProtocolCodecFilter filter= new ProtocolCodecFilter(new ObjectSerializationCodecFactory());
  3. chain.addLast("objectFilter",filter);

3、 接收对象

  1. public void messageReceived(IoSession session, Object message) throws Exception {
  2. //我们己设定了服务器解析消息的规则一个Userinfo对象为单位传输:
  3. Userinfo us=(Userinfo)message;
  4. }

案例:

Server

  1. package com.vince.mina;
  2. import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
  3. import org.apache.mina.filter.codec.ProtocolCodecFilter;
  4. import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
  5. import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
  6. import org.apache.mina.transport.socket.SocketAcceptor;
  7. import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
  8. import java.io.IOException;
  9. import java.net.InetSocketAddress;
  10. /**
  11. */
  12. public class Server {
  13. public static void main(String[] args) {
  14. //创建一个非阻塞的Server端Socket NIO
  15. SocketAcceptor acceptor = new NioSocketAcceptor();
  16. DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
  17. //设定一个过滤器,一行一行的读取数据(/r/n)
  18. //chain.addLast("myChin",new ProtocolCodecFilter(new TextLineCodecFactory()));
  19. //设定过滤器以对象为单位读取数据
  20. chain.addLast("objectFilter",new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
  21. //设置服务器端的消息处理器
  22. acceptor.setHandler(new MinaServerHandler());
  23. int port = 9999; //服务器的端口号
  24. try {
  25. //绑定端口,启动服务器(不会阻塞,立即返回)
  26. acceptor.bind(new InetSocketAddress(port));
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. System.out.println("Mina Server running, listener on : "+ port);
  31. }
  32. }

MinaServerHandler

  1. package com.vince.mina;
  2. import org.apache.mina.core.service.IoHandlerAdapter;
  3. import org.apache.mina.core.session.IoSession;
  4. /**
  5. * 服务器端的消息处理器
  6. */
  7. public class MinaServerHandler extends IoHandlerAdapter {
  8. //一次会话被打开
  9. @Override
  10. public void sessionOpened(IoSession session) throws Exception {
  11. super.sessionOpened(session);
  12. System.out.println("welcome client "+session.getRemoteAddress());
  13. }
  14. //会话关闭
  15. @Override
  16. public void sessionClosed(IoSession session) throws Exception {
  17. super.sessionClosed(session);
  18. System.out.println("client closed");
  19. }
  20. //接收消息
  21. @Override
  22. public void messageReceived(IoSession session, Object message) throws Exception {
  23. super.messageReceived(session, message);
  24. //String msg = (String) message;//接收到的消息对象
  25. Message msg = (Message) message;
  26. System.out.println("收到客户端发来的消息:"+msg);
  27. msg.setInfo("吃好吃的");
  28. //向客户端发送消息对象
  29. session.write(msg);
  30. }
  31. }

Client

  1. package com.vince.mina;
  2. import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
  3. import org.apache.mina.core.future.ConnectFuture;
  4. import org.apache.mina.filter.codec.ProtocolCodecFilter;
  5. import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
  6. import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
  7. import org.apache.mina.transport.socket.nio.NioSocketConnector;
  8. import java.net.InetSocketAddress;
  9. import java.util.Scanner;
  10. /**
  11. */
  12. public class Client {
  13. public static void main(String[] args) {
  14. //创建连接
  15. NioSocketConnector connector = new NioSocketConnector();
  16. DefaultIoFilterChainBuilder chain = connector.getFilterChain();
  17. // chain.addLast("myChin",new ProtocolCodecFilter(new TextLineCodecFactory()));
  18. //设定过滤器以对象为单位读取数据
  19. chain.addLast("objectFilter",new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
  20. connector.setHandler(new MinaClientHandler());
  21. connector.setConnectTimeoutMillis(10000);
  22. //连接服务器
  23. ConnectFuture cf = connector.connect(new InetSocketAddress("localhost",9999));
  24. cf.awaitUninterruptibly();//等待连接成功
  25. Scanner input = new Scanner(System.in);
  26. while(true) {
  27. // System.out.println("请输入:");
  28. // String info = input.nextLine();
  29. // //发送消息
  30. // cf.getSession().write(info);
  31. //以对象的方式传输数据
  32. Message msg = new Message();
  33. System.out.println("form:");
  34. msg.setFrom(input.nextLine());
  35. System.out.println("to:");
  36. msg.setTo(input.nextLine());
  37. System.out.println("info:");
  38. msg.setInfo(input.nextLine());
  39. msg.setType("send");
  40. cf.getSession().write(msg);
  41. }
  42. //等待服务器连接关闭,结束长连接
  43. // cf.getSession().getCloseFuture().awaitUninterruptibly();
  44. // connector.dispose();//关闭连接
  45. }
  46. }

MinaClientHandler

  1. package com.vince.mina;
  2. import org.apache.mina.core.service.IoHandlerAdapter;
  3. import org.apache.mina.core.session.IoSession;
  4. import javax.sound.midi.Soundbank;
  5. /**
  6. */
  7. public class MinaClientHandler extends IoHandlerAdapter {
  8. @Override
  9. public void sessionOpened(IoSession session) throws Exception {
  10. super.sessionOpened(session);
  11. System.out.println("sessionOpened");
  12. }
  13. @Override
  14. public void sessionClosed(IoSession session) throws Exception {
  15. super.sessionClosed(session);
  16. System.out.println("sessionClosed");
  17. }
  18. @Override
  19. public void messageReceived(IoSession session, Object message) throws Exception {
  20. super.messageReceived(session, message);
  21. //String msg = (String) message;
  22. Message msg = (Message)message;
  23. System.out.println(msg);
  24. }
  25. }

Message

  1. package com.vince.mina;
  2. import java.io.Serializable;
  3. /**
  4. */
  5. public class Message implements Serializable {
  6. private String from;
  7. private String to;
  8. private String type;
  9. private String info;
  10. public String getFrom() {
  11. return from;
  12. }
  13. public void setFrom(String from) {
  14. this.from = from;
  15. }
  16. public String getTo() {
  17. return to;
  18. }
  19. public void setTo(String to) {
  20. this.to = to;
  21. }
  22. public String getType() {
  23. return type;
  24. }
  25. public void setType(String type) {
  26. this.type = type;
  27. }
  28. public String getInfo() {
  29. return info;
  30. }
  31. public void setInfo(String info) {
  32. this.info = info;
  33. }
  34. @Override
  35. public String toString() {
  36. return "Message{" +
  37. "from='" + from + '\'' +
  38. ", to='" + to + '\'' +
  39. ", type='" + type + '\'' +
  40. ", info='" + info + '\'' +
  41. '}';
  42. }
  43. }