Java网络编程笔记(三):点对点通信(Socket基于TCP协议)

来源:互联网 发布:易语言自动关注源码 编辑:程序博客网 时间:2024/06/04 23:47
使用Socket进行通信,需要有客户机和服务器。客户机和服务器可以在同一台机器上,但客户机和服务器处理的信息及信息处理方式是不同的,可以分为客户机程序和服务器程序。本实例介绍实现点对点通信,即一个服务器端监听一个客户端的请求的通信。
实现点对点通信的技术要点如下:
Socket通常作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过Socket向网络发出请求或者应答网络请求。Socket是在建立网络连接时使用。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。
对于一个网络连接来说,socket是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。
Socket服务器端需要在某个端口上开启服务器端类型的类: java.net.ServerSocket。通过accept()方法用于产生"阻塞",直到接收到一个连接,并且返回一个客户端的Socket对象实例。"阻塞"是使程序运行暂时"停留"在这个地方,直到一个会话产生,然后程序继续;通常"阻塞"是由循环产生的。
Socket客户端根据服务器端的IP地址和端口号创建一个Socket对象,连接服务器。
服务器端持有ServerSocket对象,客户端持有Socket对象,服务器端的ServerSocket对象从服务器端指向客户端,而客户端的Socket对象从客户端指向服务器端,就像在服务器端和客户端建立了两条单向的管道。
服务器端程序
package core;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;class SocketServer {// Socket服务器端private int port; // 端口号public SocketServer(int port) {this.port = port;start();}private void start() {// 启动服务器端的方法try {ServerSocket serverSocket = new ServerSocket(port);// 根据端口创建服务器System.out.println("服务器已启动,监听端口号为:" + port);System.out.println("正在等待客户端连接。。。。。");Socket socketAccept = serverSocket.accept();// 挂起等待客户的请求BufferedReader in = new BufferedReader(new InputStreamReader(socketAccept.getInputStream()));// 获得(读取客户端的数据流)PrintWriter out = new PrintWriter(socketAccept.getOutputStream(), true); // 获得写往客户端的(数据输出流),true表示自动刷新out.println("服务器端连接成功。。。。");out.println("输入exit断开与服务器的连接");boolean done = false;while (!done) {String line = in.readLine();// 读取客户端每行的内容//System.out.println("line : "+line);if (line == null)done = true;else {System.out.println("客户端传来的内容: " + line);String message = infoUpperCase(line);// 变成大写再传回客户端去out.println("从服务器端口发送的内容 "+message); //--该处的print要加ln,否则就会无法往客户端传递消息if (line.trim().equals("exit")) // 退出判断done = true;}}socketAccept.close();  //关闭通信资源} catch (IOException e) {System.out.println("启动服务器端出现错误:"+e.getMessage());}}public String infoUpperCase(String line) {return line.toUpperCase(); // 将字符串大写}}public class TextSocketServer {public static void main(String[] args) {try {SocketServer server=new SocketServer(8080);} catch (Exception e) {System.out.println("测试服务器端监听出错: "+e.getMessage());}}}
客户端程序
package core;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.InetAddress;import java.net.Socket;class Client { // Socket客户端private String host; // IP地址private int port; // 端口号public Client(String host, int port) {this.host = host;this.port = port;connectSocket();// 调用连接方法}public void connectSocket() {Socket socketConn; // 声明客户端的Socket连接try {if (host.equals("localhost") || host.equals("127.0.0.1")) {// 判断IP地址(域名)如果是本机localhostsocketConn = new Socket(InetAddress.getLocalHost(), port);// 创建本地Socket连接//如果该方法InetAddress.getLocalHost()报错,则要在sudo vi /private/etc/hosts 中添加本机地址与你主机名的映射,类似  127.0.0.1 主机名//然后终端执行命令 dscacheutil -flushcache,之后主机地址便可正常解析} else {socketConn = new Socket(InetAddress.getByName(host), port);// 创建远程socket连接}BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));// 获得从键盘输入的流PrintWriter out = new PrintWriter(socketConn.getOutputStream(), true);// 往服务器写内容的数据流// 从服务器获得信息BufferedReader in = new BufferedReader(new InputStreamReader(socketConn.getInputStream()));// 接收服务器发送内容的输入流System.out.println("服务器信息:" + in.readLine());System.out.println("服务器信息:" + in.readLine());System.out.println("请输入>");boolean done = false;while (!done) {String line = stdin.readLine();// 获得从键盘输入的每行字符out.println(line);// 发送到服务器端  --该处的print要加ln,否则就会无法往服务器端传递消息if (line.equalsIgnoreCase("exit")) // 读到exit则结束循环done = true;String info = in.readLine(); // 从服务器读取字符串System.out.println("服务器信息:" + info);// 显示从服务器发送来的数据if (!done)System.out.println("请输入>");}socketConn.close(); // 关闭资源} catch (SecurityException e) {System.out.println("连接服务器出现安全问题!"+e.getMessage());} catch (IOException e) {System.out.println("连接服务器出现I/O问题!"+e.getMessage());}}}public class TextSocketClient {// Socket客户端类public static void main(String[] args) {try {new Client("localhost", 8080); // IP地址为本机,端口为8080} catch (Exception e) {System.out.println("测试客户端连接出错:" + e.getMessage());}}}

客户端程序运行截图


服务器端程序运行截图


源程序解读
(1)SocketServer类构造方法传入端口参数和调用本类的start()方法来启动服务器端监听客户端的信息。
(2)start()方法创建服务器端的ServerSocket对象,服务器端ServerSocket对象的accept()方法创建客户端的Socket对象,挂起等待客户端的请求。根据getInputStream()方法获取客户端的数据输入流创建缓冲对象。根据getOutputStream()方法获得写完客户端的数据输出流。运用标识为真条件循环,根据缓冲对象的readLine()方法读取客户端每行内容,将读取的内容经过大写处理后输出到客户端,如果传来的数据是exit则设标识为假,退出循环。最后释放有关的通信资源。
(3)Client类的构造方法初始主机和端口并调用connectSocket()方法来调用相关主机连接和获得服务器端信息。
(4)connetSocket()方法判断传入的主机,如果是本机则创建本地Socket对象,否则创建远程Socket连接对象。根据封装从键盘输入的流创建缓冲读对象,根据getOutputStream()方法获得服务器端写内容的数据流创建写数据流。运用标识为条件循环读取键盘输入的每行字符,如果读取的数据为exit则退出循环。缓冲读对象的readLine()方法获得从服务器端读取的信息。
(5)我在调试代码时遇到两个问题。问题1:创建本地Socket连接时,方法InetAddress.getLocalHost()报错
socketConn = new Socket(InetAddress.getLocalHost(), port);// 创建本地Socket连接
这是因为InetAddress.getLocalHost()要去/private/etc/hosts地址查找你主机名和IP地址的映射关系,它没有找到就报错了。
解决办法:
1.在sudo vi /private/etc/hosts 中添加本机地址与你主机名的映射,类似 127.0.0.1 主机名
2. 在终端执行命令 dscacheutil -flushcache,之后主机地址便可正常解析
问题2:在控制台输入字符串后,按回车没有反应
原因:stdin.readLine()方法从键盘输入的每行字符后,out获得输出流,但是它的print方法必须加ln,否则就会无法往服务器端传递消息
解决办法
                                String line = stdin.readLine();// 获得从键盘输入的每行字符out.println(line);// 发送到服务器端  --该处的print要加ln,否则就会无法往服务器端传递消息






阅读全文
0 1
原创粉丝点击