JAVA之Socket编程

Socket编程就是通过Socket类来编写网络通信程序,对于网络通信程序,分为两个,一个是服务器程序,一个是客户端程序。服务器程序创建一个ServerSocket对象(服务器套接字),通过调用accept()方法来接受来自客户端的连接请求,客户端程序创建一个Socket对象来连接服务器,连接请求成功后,服务器同时创建一个新的Socket与客户端建立连接,服务器继续等待新的请求。


一、客户端向服务器发送消息

服务器端:


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

public class Server {

	DataInputStream din;
	DataOutputStream dout;
	ServerSocket ss;
	Socket sc;
	
	public Server() {
		try {
			ss = new ServerSocket(9999); //创建服务器套接字
			sc = ss.accept(); //等待来自客户端的连接请求
			din = new DataInputStream(sc.getInputStream()); //获取数据输入流
			String msg = din.readUTF();
			System.out.println("客户端说:" + msg);
			din.close();
			sc.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		new Server();
	}
}


在上述服务器端代码中,通过accept来接收客户端的请求,这个请求是阻塞的,也就是说,如果没有客户端连接进来,服务器端就一直停留在接收状态,即不会执行接下来的代码,当客户端连接进来之后,通过数据输入流来读取客户端发来的消息,然后输出,结束时需关闭IO流和Socket。

客户端:

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

public class Client {

	DataInputStream din;
	DataOutputStream dout;
	Socket sc;
	
	public Client() {
		try {
			sc = new Socket("127.0.0.1", 9999); //连接服务器
			dout = new DataOutputStream(sc.getOutputStream()); //获取数据输出流
			String msg = "hello server";
			dout.writeUTF(msg);
			dout.close();
			sc.close();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		new Client();
	}
}

在上述客户端代码中也一样,通过Socket来连接服务器,连接成功后对服务器放送消息,结束时也需要关闭IO流和Socket。

上述程序,是简单的客户端向服务器发送消息,也就是一个简单的单向通信的程序。


二、服务器端和客户端互发消息


上面的只是客户端对服务器发送消息,现在来看一下两者之间可以互发消息的程序。

服务器端:

import javax.swing.*;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.*;
import java.io.*;

public class ChatServer extends JFrame implements ActionListener {

	JButton jb = new JButton("发送");
	JTextField jtf = new JTextField(20);
	JTextArea jta = new JTextArea();
	JScrollPane jsp = new JScrollPane(jta);
	JPanel jp = new JPanel();
	PrintWriter pw = null;
	
	public ChatServer() {
		this.setTitle("服务器端");
		this.setSize(350, 250);
		this.setResizable(false);
		this.setVisible(true);
		this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
		this.setLocation(500, 300);
		jta.setDisabledTextColor(Color.black);
		jb.addActionListener(this);
		jp.add(jtf);
		jp.add(jb);
		jta.setEnabled(false);
		this.add(jsp);
		this.add(jp,"South");
		
		try {
			ServerSocket ss = new ServerSocket(9999);
			Socket s = ss.accept();
			InputStreamReader isr = new InputStreamReader(s.getInputStream());
			BufferedReader br = new BufferedReader(isr);
			pw = new PrintWriter(s.getOutputStream(), true);
			while(true) {
				String xinxi = br.readLine();
				jta.append("客户端说:" + xinxi + "\n\r");
			}
			
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource() == jb) {
			String xinxi = jtf.getText();
			jta.append("我对客户端说:" + xinxi + "\n\r");
			pw.println(xinxi);
			jtf.setText("");
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new ChatServer();
	}

}


客户端:

import javax.swing.*;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.*;
import java.io.*;

public class ChatClient extends JFrame implements ActionListener {

	JButton jb = new JButton("发送");
	JTextField jtf = new JTextField(20);
	JTextArea jta = new JTextArea();
	JScrollPane jsp = new JScrollPane(jta);
	JPanel jp = new JPanel();
	PrintWriter pw = null;
	DataInputStream din;
	DataOutputStream dout;
	
	public ChatClient() {
		this.setTitle("客户端");
		this.setSize(350, 250);
		this.setResizable(false);
		this.setVisible(true);
		this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
		this.setLocation(500, 300);
		jta.setDisabledTextColor(Color.black);
		jb.addActionListener(this);
		jp.add(jtf);
		jp.add(jb);
		jta.setEnabled(false);
		jta.setLineWrap(true);
		this.add(jsp);
		this.add(jp,"South");
		jtf.addKeyListener(new KeyListener() {
			
			@Override
			public void keyTyped(KeyEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void keyReleased(KeyEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void keyPressed(KeyEvent e) {
				int key = e.getKeyCode();
				if(key == 10) {
					String xinxi = jtf.getText();
					jta.append("我对服务器说:" + xinxi + "\r\n");
					try {
						dout.writeUTF(xinxi);
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					jtf.setText("");
				}
				
			}
		});
		try {
			Socket s = new Socket("127.0.0.1", 8888);
			din = new DataInputStream(s.getInputStream());
			dout = new DataOutputStream(s.getOutputStream());
			while(true) {
				String xinxi = din.readUTF();
				jta.append("服务器说:" + xinxi + "\r\n");
			}
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == jb) {
			String xinxi = jtf.getText();
			if(!xinxi.equals("")) {
				jta.append("我对服务器说:" + xinxi + "\r\n");
				try {
					dout.writeUTF(xinxi);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				jtf.setText("");
			}
			else {
				
			}
		}
	}
	
	public static void main(String[] args) {
		new ChatClient();
	}

}


上述代码写的就是服务器端和客户端可以互发消息的一个程序,通过一个while死循环来不断接收来自客户端或者服务器端的消息,并且输出到JTextArea的文本域中,输入消息则是通过读取文本框中的内容,通过一个按钮将他发送到服务器端或者客户端,两段代码其实差的不多。


三、多个客户端同时连接到服务器端


一个服务器只能接收一个来自客户端的请求,这显然是不能满足我们的要求的,那么,如何来实现多个客户端同时连接到服务器端呢?这就要用到线程了,每当服务器接收到一个来自客户端的请求时,我们就创建一个线程,让这个线程去处理该客户端,我们可以这样做:

while(flag) {
		try {
			Socket sc = ss.accept();
			ServerThread st = new ServerThread(sc);
			st.start();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
这样就可以处理多客户端同时连接服务器端的问题了。但是呢?我们想要客户端与客户端之间发送消息该怎么办呢?那么就需要服务器端这个桥梁,一个客户端把消息发送到服务器端,服务器端再把消息发送到另一个客户端,那么服务器怎么知道我想要发送的消息是发送到这个客户端呢?那么可以这么做,我们创建一个Vector对象用来保存当前连接到服务器端的线程,然后当一个客户端想要发送消息给另一个客户端时,通过遍历Vector来找到那个客户端,然后就可以发送给那个客户端消息了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值