Java网络编程——基于TCP的Socket编程

一、基于TCP的Socket通信

1、TCP协议:TCP协议是面向连接的、可靠的、有序的,以字节流方式传输数据的通信协议。客户端与服务器要想实现通信,首先需要建立连接。

2、Java提供的基于TCP协议实现网络通信的类为:客户端的Socket类、服务器端的ServerSocket类。

3、Socket通信模型,见下图(摘自慕课网)


4、Socket通信的实现步骤:

(1)创建ServerSocket和Socket对象

(2)打开Socket的输入/输出流

(3)从输入/输出流中读/写数据

(4)关闭相关资源


二、Socket编程实例

1、非多线程的情况

服务器端:

ServerDemo.java

public class ServerDemo {
	public static void main(String[] args) throws IOException {
		ServerSocket server = null;
		Socket client = null;
		InputStream in = null;
		InputStreamReader reader = null;
		BufferedReader bufReader = null;
		OutputStream out = null;
		PrintWriter writer = null;
		
		try {
			//1、创建服务器端socket,并绑定9999端口,绑定端口之后,服务器一直监听9999端口的请求
			server = new ServerSocket(9999);
			System.out.println("------服务器已启动,等待客户端信息------");
			//2、服务器端接收到客户端的请求,建立连接
			client = server.accept();
			
			//3、将客户的请求数据以输入流的形式读取出来
			in = client.getInputStream();
			reader = new InputStreamReader(in);
			bufReader = new BufferedReader(reader);
			String msg = null;
			while((msg = bufReader.readLine()) != null) {
				System.out.println("收到客户端的信息:" + msg);
			}
			//4、关闭输入流
			client.shutdownInput();
			
			//5、通过输出流向客户端发送信息
			out = client.getOutputStream();
			writer = new PrintWriter(out);
			writer.write("我是服务器,我已经收到了你的信息!");
			writer.flush();
			//6、关闭输出流
			client.shutdownOutput();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			//7、程序最后一定要关闭资源
			if(in != null)
				in.close();
			if(reader != null) 
				reader.close();
			if(bufReader != null)
				bufReader.close();
			if(out != null)
				out.close();
			if(writer != null)
				writer.close();
			if(client != null)
				client.close();
			if(server != null)
				server.close();
		}
	}
}
客户端:

ClientDemo.java

public class ClientDemo {
	public static void main(String[] args) throws IOException {
		Socket client = null;
		InputStream in = null;
		InputStreamReader reader = null;
		BufferedReader bufReader = null;
		OutputStream out = null;
		PrintWriter writer = null;
		
		try {
			 //1、新建客户端socket,指明需要连接的服务器地址和端口号
			 //如果是本机,地址可以是localhost或者127.0.0.1
			client = new Socket("localhost", 9999);
			System.out.println("------客户端准备与服务器端建立连接------");
			
			//2、建立连接后通过输出流向服务器端发送信息
			out = client.getOutputStream();
			writer = new PrintWriter(out);
			writer.write("我是客户端,你收到我的请求了吗?");
			writer.flush();
			//3、关闭输出流
			client.shutdownOutput();
			
			//4、将服务器端的响应以输出流的形式读取出来
			in = client.getInputStream();
			reader = new InputStreamReader(in);
			bufReader = new BufferedReader(reader);
			String msg = null;
			while((msg = bufReader.readLine()) != null) {
				System.out.println("收到服务器的应答:" + msg);
			}
			//5、关闭输出流
			client.shutdownInput();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			//6、程序的最后一定要关闭资源
			if(in != null)
				in.close();
			if(reader != null) 
				reader.close();
			if(bufReader != null)
				bufReader.close();
			if(out != null)
				out.close();
			if(writer != null)
				writer.close();
			if(client != null)
				client.close();
		}
	}
}

2、多线程的情况(即一个服务器端可以不断接收多个客户端的请求)

服务器端入口:

ServerThreadMain.java

public class ServerThreadMain {
	public static void main(String[] args) {
		ServerSocket server = null;
		Socket client = null;
		try {
			server = new ServerSocket(9999);
			System.out.println("------服务器已启动,等待客户端信息------");

			while(true) {
				client = server.accept();
				ServerThread thread = new ServerThread(client);
				thread.start();
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

这里写了一个死循环,代表服务器端一直接收客户端的请求,每接收到一个客户端请求,服务器端会新启一个线程进行处理。

代表服务器端核心处理的线程:

ServerThread.java

public class ServerThread extends Thread {
	public Socket client;
	
	public ServerThread(Socket client) {
		this.client = client;
	}
	
	public void run() {
		InputStream in = null;
		InputStreamReader reader = null;
		BufferedReader bufReader = null;
		OutputStream out = null;
		PrintWriter writer = null;
		
		try {			
			in = client.getInputStream();
			reader = new InputStreamReader(in);
			bufReader = new BufferedReader(reader);
			String msg = null;
			while((msg = bufReader.readLine()) != null) {
				System.out.println("收到客户端的信息:" + msg);
			}
			client.shutdownInput();
			
			out = client.getOutputStream();
			writer = new PrintWriter(out);
			writer.write("我是服务器,我已经收到了你的信息!");
			writer.flush();
			client.shutdownOutput();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(in != null)
					in.close();
				if(reader != null) 
					reader.close();
				if(bufReader != null)
					bufReader.close();
				if(out != null)
					out.close();
				if(writer != null)
					writer.close();
				if(client != null)
					client.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
客户端代码与非多线程的客户端代码相同,不再赘述。


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值