前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java Socket编程基础

Java Socket编程基础

作者头像
亦山
发布2019-05-25 09:51:18
1K0
发布2019-05-25 09:51:18
举报

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1432226

1.简述:

Java Socket编程时对于TCP/IP 协议层的通信进行封装,简化了相关的一些操作。//待续

2.Socket 通信时序图
  3.Socket 数据流的交互
4.单客户端和服务器通信的简单例子:

服务器端代码:

代码语言:javascript
复制
package com.lou.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class TestServer {
public static void main(String[] args) throws IOException {
	//1.创建一个Server Socket
	ServerSocket server = new ServerSocket();
	// 2.绑定监听指定的端口
	InetSocketAddress address = new InetSocketAddress("localhost",18824);
	server.bind(address);
	// 3.接受此端口的通信请求
	Socket socket = server.accept();
	// 在没有客户端对其进行相应前,下面的代码不会执行,将一直阻塞
	
	//服务器端的输出流和输入流获取
	BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
	PrintWriter writer = new PrintWriter(socket.getOutputStream(),true);
	
	//来自键盘的输入数据
	BufferedReader keyword=new BufferedReader(new InputStreamReader(System.in));
	
	while(true)
	{
		if(reader.ready())
		{
			// 捕捉来自客户端发来的消息     客户端没有发消息过来时,reader.ready() 为false, 循环检测是否有数据,有测打印出来
			String info = reader.readLine();
			System.out.println("Client:"+info);
		}
		if(keyword.ready())
		{
			//捕获来自服务器端另外一个输入流 : 键盘的数据。如果有数据,则发送给客户端
			String  test = keyword.readLine();
			writer.println(test);
			System.out.println("Server:"+test);
		}
		
	}
}
}

客户端代码:

代码语言:javascript
复制
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;


public class ClientSocket {

	public static void main(String[] args) throws UnknownHostException, IOException {
		
		//1.创建一个Server Socket
		Socket socket = new Socket();
		
		// 2.连接到指定的 server socket,指定IP 和端口号
		InetSocketAddress address = new InetSocketAddress("localhost",18824);
		socket.connect(address);
		
		// 3.连接成功后,获取相应的输入输出流,进行数据交互
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
		
		BufferedReader keyword=new BufferedReader(new InputStreamReader(System.in));
		
		while(true)
		{
			// 捕捉来自服务器端发来的消息   服务器端没有发消息过来时,br.ready() 为false, 循环检测是否有数据,有测打印出来
			if(br.ready())
			{
				String info = br.readLine();
				System.out.println("Server:"+info);
			}
			
			//捕获来自服务器端另外一个输入流 : 键盘的数据。如果有数据,则发送给服务器端
			if(keyword.ready())
			{
				String  test = keyword.readLine();
				pw.println(test);
				System.out.println("Client:"+test);
			}
			
		}
		

	}

}

 运行结果:

5.Socket 多客户端单服务器之间的通信:

       上面的这个例子只能支持一个服务器端和一个客户端的通信,因为 客户端内 server.accept() 方法只执行了一次,只能返回一个Socket 连接。可以在服务端接受多个Socket,这时候的Socket应当放在一个线程里,让它有生命周期,来使用客户端和服务端的自由通信。

代码语言:javascript
复制
package com.lou.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class TestServer {
public static void main(String[] args) throws IOException {
	//1.创建一个Server Socket
	ServerSocket server = new ServerSocket();
	// 2.绑定监听指定的端口
	InetSocketAddress address = new InetSocketAddress("localhost",18824);
	server.bind(address);
	// 3.接受此端口的通信请求
	
	while(true)
	{
		//循环调用accept方法,返回相应的Socket
		Socket socket = server.accept();
		//使用线程,将每一个Socket都封装到线程内,这个每个接受的Socket可以自由的跟服务器通信了
		new Thread(new SocketHandler(socket)).start();
	}

}
}
代码语言:javascript
复制
package com.lou.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class SocketHandler implements Runnable {

	private Socket socket;
	
	public SocketHandler(Socket socket)
	{
		this.socket =socket;
	}
	@Override
	public void run() {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			PrintWriter writer = new PrintWriter(socket.getOutputStream(),true);
			//来自键盘的输入数据
			BufferedReader keyword=new BufferedReader(new InputStreamReader(System.in));
			boolean flag = true;
			
			while(flag)
			{
				if(reader.ready())
				{
					// 捕捉来自客户端发来的消息     客户端没有发消息过来时,reader.ready() 为false, 循环检测是否有数据,有测打印出来
					String info = reader.readLine();
					System.out.println("Client "+socket.getPort() +":"+info);
					
					//如果对方输入BYE,关闭回话
					if("BYE" == info)
					{
						socket.close();
						flag = false;
					}
				}
				if(keyword.ready())
				{
					//捕获来自服务器端另外一个输入流 : 键盘的数据。如果有数据,则发送给客户端
					String  test = keyword.readLine();
					writer.println(test);
					System.out.println("Server:"+test);
					
					
				}
				
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}
代码语言:javascript
复制
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;


public class ClientSocket {

	public static void main(String[] args) throws UnknownHostException, IOException {
		
		//1.创建一个Server Socket
		Socket socket = new Socket();
		
		// 2.连接到指定的 server socket,指定IP 和端口号
		InetSocketAddress address = new InetSocketAddress("localhost",18824);
		socket.connect(address);
		
		// 3.连接成功后,获取相应的输入输出流,进行数据交互
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
		
		BufferedReader keyword=new BufferedReader(new InputStreamReader(System.in));
		
		while(true)
		{
			// 捕捉来自服务器端发来的消息   服务器端没有发消息过来时,br.ready() 为false, 循环检测是否有数据,有测打印出来
			if(br.ready())
			{
				String info = br.readLine();
				System.out.println("Server:"+info);
			}
			
			//捕获来自服务器端另外一个输入流 : 键盘的数据。如果有数据,则发送给服务器端
			if(keyword.ready())
			{
				String  test = keyword.readLine();
				if("BYE" == test)
				{
					br.close();
					pw.close();
					socket.close();
				}
				pw.println(test);
				System.out.println("Client:"+test);
			}
			
		}
		

	}

}
6. 简易聊天工具的实现:

    实现的主要思路:

   a.在服务器端设置一个主线程,监听特定的一个接口,为每一个socket请求创建一个对话框和相应的处理。

主线程MainThread代码:

代码语言:javascript
复制
package com.lou.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/*
 * server的主线程,监听socket端口,为每一个Socket 创建一个对话框
 */
public class MainThread extends Thread{
	
	public List<Socket> sockets = new ArrayList<Socket>();
	@Override
	public void run() {
		//1.创建一个Server Socket
		ServerSocket server =null;
		try {
			server = new ServerSocket();
			InetSocketAddress address = new InetSocketAddress("localhost",18824);
			server.bind(address);
			while(true)
			{
				
				//循环调用accept方法,返回相应的Socket
				Socket socket = server.accept();
				sockets.add(socket);
				
				// 为每一个请求的Socket提供 界面 "会话"
				ServerGUI serverGUI = new ServerGUI(socket);
				//创建监听socket 数据流输入信息,有数据输入,则更新到GUI
				new Thread(new SocketInfoUpdater(serverGUI)).start();
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	public static void main(String[] args) {

		new MainThread().start();
	}

}

b.定义一个监听线程,用来处理 socket发送过来的数据信息,及时更新到GUI上,和 server GUI 上的发送按钮的事件相应,来发送数据。

事件和输入流监听线程SocketInfoUpdater.java:

代码语言:javascript
复制
package com.lou.socket;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
 * 此线程监听serverGUI所拥有的socket是否有数据输入,如果有更新,则更新到GUI上
 */
public class SocketInfoUpdater implements Runnable,ActionListener{

	ServerGUI server;
	
	SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	public SocketInfoUpdater(ServerGUI server)
	{
		this.server = server;
	}
	@Override
	public void run() {
		Socket socket = server.socket;
		while(true)
		{
				try {
					BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
					if(reader.ready())
					{
						String info = reader.readLine();
						server.outputArea.append("Client-" +socket.getPort()+" at " + f.format(new Date()) + "\n");
						server.outputArea.append("  "+info +"\n");
					}
					
				} catch (IOException e) {
					e.printStackTrace();
				}
				
		}
	}
	
	//设置发送按钮监听,事件相应
	@Override
	public void actionPerformed(ActionEvent e) {
		String temp = server.inputArea.getText();
		SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		server.outputArea.append("Client "+server.socket.getLocalPort() +" at " + f.format(new Date()) + "\n");
		server.outputArea.append("  " + temp + "\n");
        this.sendInfo(temp);
        server.inputArea.setText("");

	}

	private void sendInfo(String s) {
		try {
			PrintWriter pw = new PrintWriter(server.socket.getOutputStream(),
					true);
			pw.println(s);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

c. 服务器端界面的设计:

服务器端界面设计 ServerGUI.java:

代码语言:javascript
复制
package com.lou.socket;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.io.IOException;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class ServerGUI extends JFrame {

	public final Socket socket;
	//交互对话框中接收数据显示区
	final JTextArea outputArea = new JTextArea(70, 70);
	//输入区域
	final JTextArea inputArea = new JTextArea(70, 70);
	final JScrollPane outputScroll = new JScrollPane(outputArea);
	final JScrollPane inputScroll = new JScrollPane(inputArea);

	public ServerGUI(Socket socket1) throws IOException {
        
		//传入特定的socket
		this.socket = socket1;
		this.setTitle("Server");
		Container container = getContentPane();
		JPanel pane = new JPanel();
		container.setLayout(new BorderLayout());
		pane.setLayout(new GridLayout(2, 1, 5, 5));

		inputScroll.setAutoscrolls(true);
		outputScroll.setAutoscrolls(true);
		pane.add(outputScroll);

		pane.add(inputScroll);

		setSize(300, 300);
		container.add(pane, BorderLayout.CENTER);
		
		JButton send = new JButton("Send");
		//为发送按钮设置发送事件
		SocketInfoUpdater updater = new SocketInfoUpdater(this);
		send.addActionListener(updater);
		container.add(send, BorderLayout.SOUTH);
		setDefaultCloseOperation(3);
		setVisible(true);
	}
}

客户端的设计:

客户端的实现比较简单,创建一个界面,然后配一个监听输入流和处理事件的监听线程就可以了。

a.客户端GUI,ClientGUI代码:

代码语言:javascript
复制
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class ClientGUI extends JFrame {

	Socket socket = null;
	final JTextArea outputArea = new JTextArea(70, 70);
	final JTextArea inputArea = new JTextArea(70, 70);
	final JScrollPane outputScroll = new JScrollPane(outputArea);
	final JScrollPane inputScroll = new JScrollPane(inputArea);

	public ClientGUI() throws IOException {

		this.setTitle("Client");
		this.initClientSocket();
		SocketInfoUpdater updater = new SocketInfoUpdater(this);
		new Thread(updater).start();
		Container container = getContentPane();
		JPanel pane = new JPanel();
		container.setLayout(new BorderLayout());
		pane.setLayout(new GridLayout(2, 1, 5, 5));

		inputScroll.setAutoscrolls(true);
		outputScroll.setAutoscrolls(true);
		pane.add(outputScroll);

		pane.add(inputScroll);

		setSize(300, 300);
		container.add(pane, BorderLayout.CENTER);
		JButton send = new JButton("Send");
		send.addActionListener(updater);
		container.add(send, BorderLayout.SOUTH);

		setDefaultCloseOperation(3);

		setVisible(true);


	}

	/*
	 * 初始化socket
	 */
	private void initClientSocket() {
		// 1.创建一个Server Socket
		socket = new Socket();

		// 2.连接到指定的 server socket,指定IP 和端口号
		InetSocketAddress address = new InetSocketAddress("localhost", 18824);
		try {
			socket.connect(address);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws IOException {
		new ClientGUI();

	}

}

b. 输入流监听和发送数据的监听线程SocketInfoUpdater.java (这个类其实和服务器端上的基本上一样,之所以把它贴出来是考虑到在后续的开发设计中,Server 端和Client端的机制有所不同):

代码语言:javascript
复制
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SocketInfoUpdater implements Runnable ,ActionListener{

	ClientGUI client;
	public SocketInfoUpdater(ClientGUI client)
	{
		this.client = client;
	}
	
	
	@Override
	public void run() {
		Socket socket = client.socket;
		
		// 循环检测输入流有没有数据传入,有则显示出来
		while(true)
		{
			
				try {
					BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
					if(reader.ready())
					{
						String info = reader.readLine();
						SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
						
						client.outputArea.append("Server "+socket.getPort() +" at " + f.format(new Date()) + "\n");
						client.outputArea.append("  "+info +"\n");
					}
					
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
	
	//设置发送按钮监听,事件相应
	@Override
	public void actionPerformed(ActionEvent e) {
		String temp = client.inputArea.getText();
		SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		client.outputArea.append("Client "+client.socket.getLocalPort() +" at " + f.format(new Date()) + "\n");
		client.outputArea.append("  " + temp + "\n");
        this.sendInfo(temp);
        client.inputArea.setText("");

	}

	private void sendInfo(String s) {
		try {
			PrintWriter pw = new PrintWriter(client.socket.getOutputStream(),
					true);
			pw.println(s);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

执行结果:

 截图1:

截图2:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014年02月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.简述:
  • 2.Socket 通信时序图
  •   3.Socket 数据流的交互
  • 4.单客户端和服务器通信的简单例子:
  • 5.Socket 多客户端单服务器之间的通信:
  • 6. 简易聊天工具的实现:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档