全屏

12.3.4 基于TCP协议的Socket编程和通信


【专业IT培训机构,真正零首付入学www.bjsxt.com


      在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的程序被称作服务器端(Server)程序,简称服务器。一旦通讯建立,则客户端和服务器端完全一样,没有本质的区别。

“请求-响应”模式:

      1. Socket类:发送TCP消息。

      2. ServerSocket类:创建服务器。

      套接字是一种进程间的数据交换机制。这些进程既可以在同一机器上,也可以在通过网络连接的不同机器上。换句话说,套接字起到通信端点的作用。单个套接字是一个端点,而一对套接字则构成一个双向通信信道,使非关联进程可以在本地或通过网络进行数据交换。一旦建立套接字连接,数据即可在相同或不同的系统中双向或单向发送,直到其中一个端点关闭连接。套接字与主机地址和端口地址相关联。主机地址就是客户端或服务器程序所在的主机的IP地址。端口地址是指客户端或服务器程序使用的主机的通信端口。

      在客户端和服务器中,分别创建独立的Socket,并通过Socket的属性,将两个Socket进行连接,这样,客户端和服务器通过套接字所建立的连接使用输入输出流进行通信。

      TCP/IP套接字是最可靠的双向流协议,使用TCP/IP可以发送任意数量的数据。

      实际上,套接字只是计算机上已编号的端口。如果发送方和接收方计算机确定好端口,他们就可以通信了。

      如图12-6所示为客户端与服务器端的通信关系图:

图12-6 客户端与服务器端的通信关系图.png

图12-6 客户端与服务器端的通信关系图

TCP/IP通信连接的简单过程:

      位于A计算机上的TCP/IP软件向B计算机发送包含端口号的消息,B计算机的TCP/IP软件接收该消息,并进行检查,查看是否有它知道的程序正在该端口上接收消息。如果有,他就将该消息交给这个程序。

      要使程序有效地运行,就必须有一个客户端和一个服务器。

通过Socket的编程顺序:

      1. 创建服务器ServerSocket,在创建时,定义ServerSocket的监听端口(在这个端口接收客户端发来的消息)。

      2. ServerSocket调用accept()方法,使之处于阻塞状态。

      3. 创建客户端Socket,并设置服务器的IP及端口。

      4. 客户端发出连接请求,建立连接。

      5. 分别取得服务器和客户端Socket的InputStream和OutputStream。

      6. 利用Socket和ServerSocket进行数据传输。

      7. 关闭流及Socket。

【示例12-7】TCP:单向通信Socket之服务器端

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 最简单的服务器端代码
 * @author Administrator
 */
public class BasicSocketServer {
	public static void main(String[] args) {
		Socket socket = null;
		BufferedWriter bw = null;
		try {
			// 建立服务器端套接字:指定监听的接口
			ServerSocket serverSocket = new ServerSocket(8888);
			System.out.println("服务端建立监听");
			// 监听,等待客户端请求,并愿意接收连接
			socket = serverSocket.accept();
			// 获取socket的输出流,并使用缓冲流进行包装
			bw = new BufferedWriter(new     
                                    OutputStreamWriter(socket.getOutputStream()));
			// 向客户端发送反馈信息
			bw.write("hhhh");
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 关闭流及socket连接
			if (bw != null) {
				try {
					bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

【示例12-8】TCP:单向通信Socket之客户端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
/**
 * 最简单的Socket客户端
 * @author Administrator
 */
public class BasicSocketClient {
	public static void main(String[] args) {
		Socket socket = null;
		BufferedReader br = null;
		try {
			/*
             * 创建Scoket对象:指定要连接的服务器的IP和端口而不是自己机器的
             * 端口。发送端口是随机的。
             */
			socket = new Socket(InetAddress.getLocalHost(), 8888);
			//获取scoket的输入流,并使用缓冲流进行包装
			br = new BufferedReader(new  
                                   InputStreamReader(socket.getInputStream()));
			//接收服务器端发送的信息
			System.out.println(br.readLine());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭流及socket连接
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

【示例12-9】TCP:双向通信Socket之服务器端

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
	public static void main(String[] args){
		Socket socket = null;
		BufferedReader in = null;
		BufferedWriter out = null;
		BufferedReader br = null;
		try {
			//创建服务器端套接字:指定监听端口
			ServerSocket server = new ServerSocket(8888);
			//监听客户端的连接
			socket = server.accept();
			//获取socket的输入输出流接收和发送信息
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new BufferedWriter(new 
                                   OutputStreamWriter(socket.getOutputStream()));
			br = new BufferedReader(new InputStreamReader(System.in));
			while (true) {
				//接收客户端发送的信息
				String str = in.readLine();
				System.out.println("客户端说:" + str);
				String str2 = "";
				//如果客户端发送的是“end”则终止连接 
				if (str.equals("end")){
					break;
				}
				//否则,发送反馈信息
				str2 = br.readLine(); // 读到\n为止,因此一定要输入换行符!
				out.write(str2 + "\n");
				out.flush();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			//关闭资源
			if(in != null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out != null){
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(br != null){
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(socket != null){
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

【示例12-10】TCP:双向通信Socket之客户端

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
	public static void main(String[] args) {
		Socket socket = null;
		BufferedReader in = null;
		BufferedWriter out = null;
		BufferedReader wt = null;
		try {
			//创建Socket对象,指定服务器端的IP与端口
			socket = new Socket(InetAddress.getLocalHost(), 8888);
			//获取scoket的输入输出流接收和发送信息
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new BufferedWriter(new 
                                   OutputStreamWriter(socket.getOutputStream()));
			wt = new BufferedReader(new InputStreamReader(System.in));
			while (true) {
				//发送信息
				String str = wt.readLine();
				out.write(str + "\n");
				out.flush();
				//如果输入的信息为“end”则终止连接
				if (str.equals("end")) {
					break;
				}
				//否则,接收并输出服务器端信息
				System.out.println("服务器端说:" + in.readLine());
			}
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 关闭资源
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (wt != null) {
				try {
					wt.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

      执行结果如图12-7与图12-8所示

图12-7示例12-9与12-10运行效果图—服务器端.png

图12-7示例12-9与12-10运行效果图—服务器端

图12-8示例12-9与12-10运行效果图—客户端.png

图12-8示例12-9与12-10运行效果图—客户端

菜鸟雷区

      运行时,要先启动服务器端,再启动客户端,才能得到正常的运行效果。

      但是,上面这个程序,必须按照安排好的顺序,服务器和客户端一问一答!不够灵活!!可以使用多线程实现更加灵活的双向通讯!!

      服务器端:一个线程专门发送消息,一个线程专门接收消息。

      客户端:一个线程专门发送消息,一个线程专门接收消息。

【示例12-11】TCP:聊天室之服务器端

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class ChatServer {
	public static void main(String[] args) {
		ServerSocket server = null;
		Socket socket = null;
		BufferedReader in = null;
		try {
			server = new ServerSocket(8888);
			socket = server.accept();
			//创建向客户端发送消息的线程,并启动
			new ServerThread(socket).start();
			// main线程负责读取客户端发来的信息
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			while (true) {
				String str = in.readLine();
				System.out.println("客户端说:" + str);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null) {
					in.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (socket != null) {
					socket.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

/**
 * 专门向客户端发送消息的线程
 * 
 * @author Administrator
 *
 */
class ServerThread extends Thread {
	Socket ss;
	BufferedWriter out;
	BufferedReader br;

	public ServerThread(Socket ss) {
		this.ss = ss;
		try {
			out = new BufferedWriter(new OutputStreamWriter(ss.getOutputStream()));
			br = new BufferedReader(new InputStreamReader(System.in));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void run() {
		try {
			while (true) {
				String str2 = br.readLine();
				out.write(str2 + "\n");
				out.flush();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(out != null){
				out.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if(br != null){
					br.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

【示例12-12】TCP:聊天室之客户端

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class ChatClient {
	public static void main(String[] args) {
		Socket socket = null;
		BufferedReader in = null;
		try {
			socket = new Socket(InetAddress.getByName("127.0.1.1"), 8888);
			// 创建向服务器端发送信息的线程,并启动
			new ClientThread(socket).start();
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			// main线程负责接收服务器发来的信息
			while (true) {
				System.out.println("服务器说:" + in.readLine());
			}
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (socket != null) {
					socket.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (in != null) {
					in.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

/**
 * 用于向服务器发送消息
 * 
 * @author Administrator
 *
 */
class ClientThread extends Thread {
	Socket s;
	BufferedWriter out;
	BufferedReader wt;

	public ClientThread(Socket s) {
		this.s = s;
		try {
			out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
			wt = new BufferedReader(new InputStreamReader(System.in));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void run() {
		try {
			while (true) {
				String str = wt.readLine();
				out.write(str + "\n");
				out.flush();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (wt != null) {
					wt.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (out != null) {
					out.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

      执行结果如图12-9与图12-10所示:

图12-9 示例12-11与12-12运行效果图—服务器端.png

图12-9 示例12-11与12-12运行效果图—服务器端

图12-10 示例12-11与12-12运行效果图—客户端.png

图12-10 示例12-11与12-12运行效果图—客户端

分类导航
点击按住视频可拖动

缩小

关闭

  • 正在学习
  • 北京总部地址:北京市海淀区西三旗街道建材城西路中腾建华商务大厦东侧二层尚学堂
  • 咨询电话:400-009-1906 010-56233821
  • Copyright 2007-2015 北京尚学堂科技有限公司
  • 京ICP备13018289号-1 京公网安备11010802015183