用java多线程实现服务器与客户端原理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用java多线程实现服务器与客户端原理相关的知识,希望对你有一定的参考价值。

请教!

服务器端:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.Vector;
public class OneToMoreServer extends JFrame implements ActionListener
JPanel contentPane;
JLabel jLabel2 = new JLabel();
JTextField jTextField2 = new JTextField("4700");
JButton jButton1 = new JButton();
JLabel jLabel3 = new JLabel();
JTextField jTextField3 = new JTextField();
JButton jButton2 = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea jTextArea1 = new JTextArea();
ServerSocket server = null;
Socket socket = null;BufferedReader instr =null;PrintWriter os=null ;
Vector vector=new Vector();
boolean serverRun=true;
boolean clientRun=true;
//Construct the frame
public OneToMoreServer()
jbInit();



class MyThread extends Thread//该线程负责接收数据
Socket socketI=null;
BufferedReader br=null;
public MyThread(Socket socket)

socketI=socket;

public void run()
try
while(clientRun)
this.sleep(100);
br= new BufferedReader(new InputStreamReader(socketI.getInputStream()));
if(br.ready()) //检查是否有数据
jTextArea1.append("接收到来自客户端("+socketI.getInetAddress().toString()+")的消息: "+br.readLine()+"\n");


catch(Exception ex)JOptionPane.showMessageDialog(null,ex.toString());



public void actionPerformed(ActionEvent e)
if(e.getSource()==jButton1)
int port=Integer.parseInt(jTextField2.getText().trim());
//监听指定端口
try

server = new ServerSocket(port);
new Thread(new ListenClient()).start();

catch(IOException ex)

JOptionPane.showMessageDialog(null,ex.toString());


if(e.getSource()==jButton2)
String msg=jTextField3.getText().trim();
if(msg.length()!=0)
sendData("hello");


//该线程负责监听指定端口
class ListenClient implements Runnable

public void run()

try
if(jButton1.getText().trim().equals("侦听"))
jButton1.setText("正在侦听...");
while(serverRun)

Socket socketI=server.accept();//有客户端连入时建立一个线程监听客户端发送的消息
vector.add(socketI);
jButton1.setText("正在聊天...");
jTextArea1.append("客户端"+socketI.getInetAddress().toString()+"已经连接到服务器\n");
MyThread t=new MyThread(socketI);
t.start();


catch(Exception ex)
JOptionPane.showMessageDialog(null,ex.toString());




private void sendData(String s)//发送数据
try
for(int i=0;i<vector.size();i++)

//怎么广播?????
//向每个客户端发送一条消息
Socket socket=(Socket)vector.get(i);
os= new PrintWriter(socket.getOutputStream());
os.println(s);
os.flush();

catch(Exception ex)



private void jbInit()
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(null);
this.setSize(new Dimension(540, 340));
this.setTitle("服务器");
jLabel2.setBounds(new Rectangle(22, 27, 72, 28));
jLabel2.setText("端口号");
jLabel2.setFont(new java.awt.Font("宋体", 0, 14));
jTextField2.setBounds(new Rectangle(113, 27, 315, 24));

jButton1.setBounds(new Rectangle(440, 28, 73, 25));
jButton1.setFont(new java.awt.Font("Dialog", 0, 14));
jButton1.setBorder(BorderFactory.createEtchedBorder());
jButton1.setActionCommand("jButton1");
jButton1.setText("侦听");
jLabel3.setBounds(new Rectangle(23, 57, 87, 28));
jLabel3.setText("请输入信息");
jLabel3.setFont(new java.awt.Font("宋体", 0, 14));
jTextField3.setBounds(new Rectangle(114, 60, 314, 24));
jTextField3.setText("");
jButton2.setText("广播");
jButton2.setActionCommand("jButton1");
jButton2.setBorder(BorderFactory.createEtchedBorder());
jButton2.setFont(new java.awt.Font("Dialog", 0, 14));
jButton2.setBounds(new Rectangle(440, 58, 73, 25));
jScrollPane1.setBounds(new Rectangle(23, 92, 493, 189));

contentPane.add(jTextField2, null);
contentPane.add(jButton1, null);
contentPane.add(jLabel3, null);
contentPane.add(jTextField3, null);
contentPane.add(jButton2, null);
contentPane.add(jScrollPane1, null);
contentPane.add(jLabel2, null);
jScrollPane1.getViewport().add(jTextArea1, null);
jButton1.addActionListener(this);
jButton2.addActionListener(this);
this.addWindowListener(new WindowAdapter()
public void windowClosing(WindowEvent e)
try
socket.close();
instr.close();
System.exit(0);
catch(Exception ex)
//JOptionPane.showMessageDialog(null,ex.toString());



);

public static void main(String arg[])
JFrame.setDefaultLookAndFeelDecorated(true);
OneToMoreServer frm=new OneToMoreServer();
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frm.setVisible(true);



客户端
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
public class Client extends JFrame implements ActionListener
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JTextField jTextField1 = new JTextField("127.0.0.1");
JLabel jLabel2 = new JLabel();
JTextField jTextField2 = new JTextField("4700");
JButton jButton1 = new JButton();
JLabel jLabel3 = new JLabel();
JTextField jTextField3 = new JTextField();
JButton jButton2 = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea jTextArea1 = new JTextArea();
BufferedReader instr =null;
Socket socket = null;
PrintWriter os=null;
public Client()
jbInit();

class MyThread extends Thread
public void run()
try
os=new PrintWriter(socket.getOutputStream());
instr=new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true)

this.sleep(100);
if(instr.ready())

jTextArea1.append("接收到来自服务器的消息: "+instr.readLine()+"\n");


catch(Exception ex)
JOptionPane.showMessageDialog(null,ex.toString());



public void actionPerformed(ActionEvent e)
if(e.getSource()==jButton1)
String ip=jTextField3.getText().trim();
int port=Integer.parseInt(jTextField2.getText().trim());
connectServer(ip,port);

if(e.getSource()==jButton2)
String s=this.jTextField3.getText().trim();
sendData(s);


private void connectServer(String ip,int port)//连接
try
if(jButton1.getText().trim().equals("连接"))
jButton1.setText("连接服务器...");
socket=new Socket(ip,port);
jButton1.setText("正在聊天");
MyThread t=new MyThread();
t.start();

catch(Exception ex)
JOptionPane.showMessageDialog(this,ex.toString());


private void sendData(String s)//发送数据
try
os = new PrintWriter(socket.getOutputStream());
os.println(s);
os.flush();
this.jTextArea1.append("向服务器发送消息:"+s+"\n");
catch(Exception ex)
JOptionPane.showMessageDialog(this,ex.toString());


private void jbInit()
contentPane = (JPanel) this.getContentPane();
jLabel1.setFont(new java.awt.Font("宋体", 0, 14));
jLabel1.setText("服务器名称");
jLabel1.setBounds(new Rectangle(20, 22, 87, 28));
contentPane.setLayout(null);
this.setSize(new Dimension(540, 340));
this.setTitle("客户端");

jTextField1.setBounds(new Rectangle(114, 26, 108, 24));
jLabel2.setBounds(new Rectangle(250, 25, 72, 28));
jLabel2.setText("端口号");
jLabel2.setFont(new java.awt.Font("宋体", 0, 14));
jTextField2.setBounds(new Rectangle(320, 27, 108, 24));

jButton1.setBounds(new Rectangle(440, 28, 73, 25));
jButton1.setFont(new java.awt.Font("Dialog", 0, 14));
jButton1.setBorder(BorderFactory.createEtchedBorder());
jButton1.setActionCommand("jButton1");
jButton1.setText("连接");
jLabel3.setBounds(new Rectangle(23, 57, 87, 28));
jLabel3.setText("请输入信息");
jLabel3.setFont(new java.awt.Font("宋体", 0, 14));
jTextField3.setBounds(new Rectangle(114, 60, 314, 24));

jButton2.setText("发送");
jButton2.setActionCommand("jButton1");
jButton2.setBorder(BorderFactory.createEtchedBorder());
jButton2.setFont(new java.awt.Font("Dialog", 0, 14));
jButton2.setBounds(new Rectangle(440, 58, 73, 25));
jScrollPane1.setBounds(new Rectangle(23, 92, 493, 189));

contentPane.add(jLabel1, null);
contentPane.add(jTextField1, null);
contentPane.add(jLabel2, null);
contentPane.add(jTextField2, null);
contentPane.add(jButton1, null);
contentPane.add(jLabel3, null);
contentPane.add(jTextField3, null);
contentPane.add(jButton2, null);
contentPane.add(jScrollPane1, null);
jScrollPane1.getViewport().add(jTextArea1, null);
jButton1.addActionListener(this);
jButton2.addActionListener(this);
this.addWindowListener(new WindowAdapter()
public void windowClosing(WindowEvent e)
try
socket.close();instr.close();os.close();System.exit(0);
catch(Exception ex)
JOptionPane.showMessageDialog(null,ex.toString());


);

public static void main(String arg[])
JFrame.setDefaultLookAndFeelDecorated(true);
Client frm=new Client();
frm.setVisible(true);

参考技术A // 在服务器上部署的程序

package wang.socket.Server;
// java 提供的网络功能包
import java.net.*;
// java 提供的输入输出的功能包
import java.io.*;

// 使用线程来处理Socket请求
public class ThreadServer

public static void main(String[] args) throws Exception

// 监听服务
ServerSocket server;
// 启动一个监听服务器
server = new ServerSocket(9999);
System.out.println("---------> 一个Socket监听服务器启动:" + server.toString());
while (true) //循环地响应客户端的请求

//获得客户端连接,也就是要建立一个Socket套接字,由于没有使用线程,多个客户端连接会排队
// ServerSocket的接收套接字的方法是采用队列并等待的方式,如果没有呼入连接,则程序在等待,不向下执行.
Socket client = server.accept();
// 创建线程,让线程去应答客户的请求
new ServerThread(client).start();





// 以线程处理客户的请求
class ServerThread extends Thread
//主程序的main函数会把创建的Socket作为参数传递给线程执行.

private Socket sk;

public ServerThread(Socket s)
this.sk = s;


@Override
public void run()
System.out.println("(一个客户请求:)" + this.sk.toString());
// 缓冲区读取器
BufferedReader in;
// 响应器
PrintWriter out;
// 取得客户端的计算机的IP地址
String remoteIP = this.sk.getInetAddress().getHostAddress();
// 取得客户端用于通讯的端口号
int remotePort = this.sk.getLocalPort();
// 在服务器的监控台上显示客户端接入的信息
System.out.println("一个客户端正在连入, IP:" + remoteIP + ", 端口: " + remotePort);

//获得 client 端的输入输出流,为进行交互做准备
try
in = new BufferedReader(new InputStreamReader(this.sk.getInputStream()));
//获得输出
out = new PrintWriter(this.sk.getOutputStream(), true);

//获得 client 端发送的数据,要注意的是客户端从一个套接字里有可能发送多行的数据。
String content;
// 只有比较明显地给出一个数据流终结的方式才好
while (!(content = in.readLine()).equals("taxend"))

System.out.println("客户端发来的消息: " + content);
out.println(content);
// 向 client 端发送响应数据

//关闭各个流
// out.flush(); 清缓冲区

out.close();
in.close();
// 一次通讯结束,可以关闭socket
this.sk.close();
catch (Exception ex)
// ex.printStackTrace();
System.out.println("客户挂断了.........");





// 在客户端部署的程序

package wang.socket.Client;

import java.net.*;
import java.io.*;

/**
*
* @author WangQingda
*/
public class AWTClient extends javax.swing.JFrame

/** Creates new form AWTClient */
public AWTClient()

initComponents();


/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents()

jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
theServerIP = new javax.swing.JTextField();
jScrollPane1 = new javax.swing.JScrollPane();
theContent = new javax.swing.JTextArea();
jButton1 = new javax.swing.JButton();
jScrollPane2 = new javax.swing.JScrollPane();
theServerOutPut = new javax.swing.JTextArea();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("测试Socket数据流");

jLabel1.setText("请输入服务器地址:");

jLabel2.setText("输入需要提交数据流:");

theServerIP.setText("127.0.0.1");

theContent.setColumns(20);
theContent.setRows(5);
jScrollPane1.setViewportView(theContent);

jButton1.setLabel("提交");
jButton1.addActionListener(new java.awt.event.ActionListener()
public void actionPerformed(java.awt.event.ActionEvent evt)
jButton1ActionPerformed(evt);

);

theServerOutPut.setColumns(20);
theServerOutPut.setRows(5);
jScrollPane2.setViewportView(theServerOutPut);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane2))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addGap(31, 31, 31)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2)
.addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 317, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel1)
.addGap(18, 18, 18)
.addComponent(theServerIP, javax.swing.GroupLayout.PREFERRED_SIZE, 167, javax.swing.GroupLayout.PREFERRED_SIZE)))))
.addContainerGap(31, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(41, 41, 41)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(theServerIP, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(layout.createSequentialGroup()
.addGap(34, 34, 34)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jButton1))
.addGroup(layout.createSequentialGroup()
.addGap(18, 18, 18)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(13, Short.MAX_VALUE))
);

pack();
// </editor-fold>

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
// TODO add your handling code here:
try
//连接 server 端
System.out.println("连接服务器 ...");
Socket client = new Socket(this.theServerIP.getText(), 9999);

//显示已连接
System.out.println("成功接入服务器.");
System.out.println();

//为发送数据做准备
System.out.println("请输入:");
// 注意字符串要以字符流的形式读入。
BufferedReader in = new BufferedReader(new StringReader(this.theContent.getText()));
// 流的输出可以从socket的输出流得到。
PrintWriter out = new PrintWriter(client.getOutputStream(), true);

// 向 server 发送数据
String outTxt;
while ((outTxt = in.readLine()) != null)
out.println(outTxt);
System.out.println("向服务器发送:"+outTxt);


out.flush();
this.theServerOutPut.append("数据已经成功向服务器发送");
//接收来自 server 的响应数据
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String inTxt;
while ((inTxt = in.readLine()) != null)
this.theServerOutPut.append(inTxt);


// 关闭各个流
in.close();
out.close();
// 客户端退出
client.close();

catch (Exception e)
e.printStackTrace();



/**
* @param args the command line arguments
*/
public static void main(String args[])
java.awt.EventQueue.invokeLater(new Runnable()

public void run()
new AWTClient().setVisible(true);

);

// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JTextArea theContent;
private javax.swing.JTextField theServerIP;
private javax.swing.JTextArea theServerOutPut;
// End of variables declaration

java自学网址,源码+原理+手写框架

一、对Kafka的认识

1.Kafka的基本概念

image

2.安装与配置

image

3.生产与消费

image

4.服务端参数配置

image

二、生产者

1.客户端开发

  • 必要的参数配置
  • 消息的发送
  • 序列化
  • 分区器
  • 生产者拦截器

image

2.原理分析

  • 整体架构
  • 元数据的更新

image

3.重要的生产者参数

image

三、消费者

1.消费者与消费组

image

2.客户端开发

  • 必要的参数配置
  • 订阅主题与分区
  • 反序列化
  • 消息消费
  • 位移提交
  • 控制或关闭消费
  • 指定位移消费
  • 再均衡
  • 消费者拦截器
  • 多线程实现
  • 重要的消费者参数

image

四、主题与分区

1.主题的管理

  • 创建主题
  • 分区副本的分配
  • 查看主题
  • 修改主题
  • 配置管理
  • 主题端参数
  • 删除主题

image

2.初识KafkaAdminCilent

  • 基本使用
  • 主题合法性验证

image

3.分区的管理

  • 优先副本的选举
  • 分区重分配
  • 复制限流
  • 修改副本因子

image

4.如何选择合适的分区数

  • 性能测试工具
  • 分区数越多吞吐量就越高吗
  • 分区数的上限
  • 考量因素

image

五、日志存储

1.文件目录布局

image

2.日志格式的演变

  • v0版本
  • v1版本
  • 消息压缩
  • 变长字段
  • v2版本

image

3.日志索引

  • 偏移量索引
  • 时间戳索引

image

4.日志清理

  • 日志删除
  • 日志压缩

image

5.磁盘存储

  • 页缓存
  • 磁盘I/O流程
  • 零拷贝

image

六、深入服务端

1.协议设计

image

2.时间轮

image

3.延时操作

image

4.控制器

image

5.参数解密

image

七、深入客户端

1.分区分配策略

image

2.消费者协调器和组协调器

image

3._consumer_offsets剖析

image

4.事务

image

八、可靠性探究

1.副本剖析

image

2.日志同步机制

image

3.可靠性分析

image

九、Kafka应用

1.命令行工具

image

2.Kafka Connect

image

3.Kafka Mirror Maker

image

4.Kafka Streams

image

十、Kafka监控

1.监控数据的来源

image

2.消费滞后

image

3.同步失效分区

image

4.监控指标说明

image

5.监控模块

image

十一、高级应用

1.过期时间(TTL)

image

2.延时队列

image

3.死信队列和重试队列

image

4.消息路由

image

5.消息轨迹

image

6.消息审计

image

7.消息代理

image

8.消息中间件选型

image

十二、Kafka与Spark的集成

1.Spark的安装及简单应用

image

2.Spark编程模型

image

3.Spark的运行结构

image

4.Spark Streaming简介

image

5.Kafka与Spark Streaming的整合

image

6.Spark SQL

image

7.Structured Streaming

image

8.Kafka与Structured Streaming的整合

image

最后

各位读者,由于本篇幅度过长,为了避免影响阅读体验,下面我就大概概括了整理了,需要的话请**点赞后点击这里免费下载文章资料!**

eaming的整合**

[外链图片转存中…(img-xHAoKQpg-1624531566896)]

最后

各位读者,由于本篇幅度过长,为了避免影响阅读体验,下面我就大概概括了整理了,需要的话请**点赞后点击这里免费下载文章资料!**

[外链图片转存中…(img-vtt5wHQV-1624531566897)]

[外链图片转存中…(img-uJ8LfbjE-1624531566897)]

[外链图片转存中…(img-54BwJh5s-1624531566898)]

以上是关于用java多线程实现服务器与客户端原理的主要内容,如果未能解决你的问题,请参考以下文章

JAVA-初步认识-第十二章-多线好处与弊端

Java总结——通过Callable接口实现多线程,生产者消费者问题,多线下载(复制)文件

java 多线程子线程唤醒主线程问题

实验二:多线程

用Java模拟多线程下的客户端与服务端数据交互

多线程原理是啥?