Java Socket编程基础

1.简述:

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

2.Socket 通信时序图

 

  3.Socket 数据流的交互

 

4.单客户端和服务器通信的简单例子:

服务器端代码:

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);
		}
		
	}
}
}


客户端代码:

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应当放在一个线程里,让它有生命周期,来使用客户端和服务端的自由通信。

 

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();
	}

}
}


 

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();
		}

	}

}


 

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代码:

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

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:

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代码:

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端的机制有所不同):

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:

 

 

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,我会尽力回答你关于Java Socket网络编程的问题。 Java Socket网络编程Java语言中常用的网络通信技术之一,它可以实现客户端与服务端之间的通信,常用于开发网络应用程序、网络游戏等。下面我们来看一个基于Java Socket网络编程的应用实例。 假设我们有一个简单的聊天室应用程序,它由一个服务端和多个客户端组成。服务端负责接收客户端连接请求,并将客户端发送的消息广播给所有连接到服务端的客户端,客户端负责向服务端发送消息并接收来自服务端的消息。 1. 服务端实现 首先,我们需要编写服务端的代码。服务端需要监听指定的端口,等待客户端的连接请求,并在接收到连接请求时为每个客户端创建一个独立的线程进行处理。以下是服务端的代码示例: ```java import java.io.*; import java.net.*; public class Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = null; boolean listening = true; try { serverSocket = new ServerSocket(4444); } catch (IOException e) { System.err.println("Could not listen on port: 4444."); System.exit(-1); } while (listening) { new ServerThread(serverSocket.accept()).start(); } serverSocket.close(); } } class ServerThread extends Thread { private Socket socket = null; public ServerThread(Socket socket) { super("ServerThread"); this.socket = socket; } public void run() { try { PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { out.println(inputLine); } out.close(); in.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 2. 客户端实现 接下来,我们需要编写客户端的代码。客户端需要连接到服务端指定的端口,并在连接成功后启动一个单独的线程用于接收来自服务端的消息。以下是客户端的代码示例: ```java import java.io.*; import java.net.*; public class Client implements Runnable { private static Socket socket = null; public static void main(String[] args) throws IOException { String hostName = "localhost"; int portNumber = 4444; try { socket = new Socket(hostName, portNumber); } catch (UnknownHostException e) { System.err.println("Don't know about host " + hostName); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to " + hostName); System.exit(1); } BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); new Thread(new Client()).start(); String userInput; while ((userInput = stdIn.readLine()) != null) { PrintWriter out = new PrintWriter(socket.getOutputStream(), true); out.println(userInput); if (userInput.equals("exit")) { break; } } socket.close(); } public void run() { try { BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("Server: " + inputLine); } in.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 以上就是一个简单的基于Java Socket网络编程的聊天室应用程序的实现。在实际开发中,我们可以根据具体需求对代码进行修改和优化,使其更符合实际业务需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亦山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值