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

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

服务器端:

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 = nullBufferedReader instr =nullPrintWriter 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=0i<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)

}

}

进程是程序在处理机中的一次运行。一个进程既包括其所要执行的指令,也包括了执行指令所需的系统资源,不同进程所占用的系统资源相对独立。所以进程是重量级的任务,它们之间的通信和转换都需要操作系统付出较大的开销。

线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己基本上不拥有系统资源,但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。所以线程是轻量级的任务,它们之间的通信和转换只需要较小的系统开销。

Java支持多线程编程,因此用Java编写的应用程序可以同时执行多个任务。Java的多线程机制使用起来非常方便,用户只需关注程序细节的实现,而不用担心后台的多任务系统。

Java语言里,线程表现为线程类。Thread线程类封装了所有需要的线程操作控制。在设计程序时,必须很清晰地区分开线程对象和运行线程,可以将线程对象看作是运行线程的控制面板。在线程对象里有很多方法来控制一个线程是否运行,睡眠,挂起或停止。线程类是控制线程行为的唯一的手段。一旦一个Java程序启动后,就已经有一个线程在运行。可通过调用Thread.currentThread方法来查看当前运行的是哪一个线程。

class ThreadTest{

public static void main(String args[]){

Thread t = Thread.currentThread()

t.setName("单线程")//对线程取名为"单线程"

t.setPriority(8)

//设置线程优先级为8,最高为10,最低为1,默认为5

System.out.println("The running thread: " + t)

// 显示线程信息

try{

for(int i=0i<3i++){

System.out.println("Sleep time " + i)

Thread.sleep(100) // 睡眠100毫秒

}

}catch(InterruptedException e){// 捕获异常

System.out.println("thread has wrong")

}

}

}

多线程的实现方法

继承Thread类

可通过继承Thread类并重写其中的run()方法来定义线程体以实现线程的具体行为,然后创建该子类的对象以创建线程。

在继承Thread类的子类ThreadSubclassName中重写run()方法来定义线程体的一般格式为:

public class ThreadSubclassName extends Thread{

public ThreadSubclassName(){

..... // 编写子类的构造方法,可缺省

}

public void run(){

..... // 编写自己的线程代码

}

}

用定义的线程子类ThreadSubclassName创建线程对象的一般格式为:

ThreadSubclassName ThreadObject =

new ThreadSubclassName()

然后,就可启动该线程对象表示的线程:

ThreadObject.start() //启动线程

应用继承类Thread的方法实现多线程的程序。本程序创建了三个单独的线程,它们分别打印自己的“Hello World!”。

class ThreadDemo extends Thread{

private String whoami

private int delay

public ThreadDemo(String s,int d){

whoami=s

delay=d

}

public void run(){

try{

sleep(delay)

}catch(InterruptedException e){ }

System.out.println("Hello World!" + whoami

+ " " +delay)

}

}

public class MultiThread{

public static void main(String args[]){

ThreadDemo t1,t2,t3

t1 = new ThreadDemo("Thread1",

(int)(Math.random()*2000))

t2 = new ThreadDemo("Thread2",

(int)(Math.random()*2000))

t3 = new ThreadDemo("Thread3",

(int)(Math.random()*2000))

t1.start()

t2.start()

t3.start()

}

}

实现Runnable接口

编写多线程程序的另一种的方法是实现Runnable接口。在一个类中实现Runnable接口(以后称实现Runnable接口的类为Runnable类),并在该类中定义run()方法,然后用带有Runnable参数的Thread类构造方法创建线程。

创建线程对象可用下面的两个步骤来完成:

(1)生成Runnable类ClassName的对象

ClassName RunnableObject = new ClassName()

(2)用带有Runnable参数的Thread类构造方法创建线程对象。新创建的线程的指针将指向Runnable类的实例。用该Runnable类的实例为线程提供 run()方法---线程体。

Thread ThreadObject = new Thread(RunnableObject)

然后,就可启动线程对象ThreadObject表示的线程:

ThreadObject.start()

在Thread类中带有Runnable接口的构造方法有:

public Thread(Runnable target)

public Thread(Runnable target, String name)

public Thread(String name)

public Thread(ThreadGroup group,Runnable target)

public Thread(ThreadGroup group,Runnable target,

String name)

其中,参数Runnable target表示该线程执行时运行target的run()方法,String name以指定名字构造线程,ThreadGroup group表示创建线程组。

用Runnable接口实现的多线程。

class TwoThread implements Runnable{

TwoThread(){

Thread t1 = Thread.currentThread()

t1.setName("第一主线程")

System.out.println("正在运行的线程: " + t1)

Thread t2 = new Thread(this,"第二线程")

System.out.println("创建第二线程")

t2.start()

try{

System.out.println("第一线程休眠")

Thread.sleep(3000)

}catch(InterruptedException e){

System.out.println("第一线程有错")

}

System.out.println("第一线程退出")

}

public void run(){

try{

for(int i = 0i <5i++){

System.out.println(“第二线程的休眠时间:”

+ i)

Thread.sleep(1000)

}

}catch(InterruptedException e){

System.out.println("线程有错")

}

System.out.println("第二线程退出")

}

public static void main(String args[]){

new TwoThread()

}

}

程序运行结果如下:

正在运行的线程: Thread[第一主线程,5,main

创建第二线程

第一线程休眠

第二线程的休眠时间:0

第二线程的休眠时间:1

第二线程的休眠时间:2

第一线程退出

第二线程的休眠时间:3

第二线程的休眠时间:4

第二线程退出


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/209690.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-04
下一篇2023-04-04

发表评论

登录后才能评论

评论列表(0条)

    保存