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

使用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地址(域名)如果是本机localhost
				socketConn = 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,否则就会无法往服务器端传递消息






  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值