Java中利用socket实现简单的服务端与客户端的通信(中级)——实现任意双向通信

时间:2023-01-21 00:00:55

本文计划采用socket实现客户端和服务端的任意双向通信,即客户端可以随时给服务端发消息,服务端也可以随时给客户端发消息,最终结果就是一个类似与QQ的聊天软件的功能。

以下代码可以直接拷贝到Eclipse中运行。

前面的两片文章都利用了socket实现了客户端与服务器的通信,我的前两片文章:

Java中利用socket实现简单的服务端与客户端的通信(入门级),实现了一个简单的客户端发送消息,服务器端接收消息的实力,没有多线程,也没有让服务器端有消息返回。 

Java中利用socket实现简单的服务端与客户端的通信(基础级),在上一篇的基础上,在服务端实现了多线程,使得服务端可以于多个客户端连接并接收他们发送的消息。


要想实现任意的双向通信,以客户端来说,时刻既需要能够发送消息,同时也需要能够随时的接收服务端发来的消息,这两个功能必须同时存在,还必须同时运行,所以这个时候就必须使用到多线程了。无论是服务端还是客户端,都至少需要多出两个线程,一个线程用于发送数据,一个线程用于接收数据。这是本文的关键。

客户端:

package client_3;

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

public class client_3 {

public static final String IP = "localhost";//服务器地址
public static final int PORT = 10000;//服务器端口号

public static void main(String[] args) {

handler();
}

private static void handler(){
try {
//实例化一个Socket,并指定服务器地址和端口
Socket client = new Socket(IP, PORT);
System.out.println("I am a client");
//开启两个线程,一个负责读,一个负责写
new Thread(new ReadHandlerThread(client)).start();
new Thread(new WriteHandlerThread(client)).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}

/*
*处理读操作的线程
*/
class ReadHandlerThread implements Runnable{
private Socket client;

public ReadHandlerThread(Socket client) {
this.client = client;
}
@Override
public void run() {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
while(true){
System.out.println("服务器说:"+in.readLine());
}
} catch (IOException e) {
e.printStackTrace();
} finally{
if(client != null){
client = null;
}
}
}
}

/*
* 处理写操作的线程
*/
class WriteHandlerThread implements Runnable{
private Socket client;

public WriteHandlerThread(Socket client) {
this.client = client;
}

@Override
public void run() {
PrintWriter out=null;
try {
out = new PrintWriter(client.getOutputStream());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));//从控制台获取输入的内容
try {
while(true){
out.println(reader.readLine());
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
client.close();
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();


}
}
可以看到,上述代码有两个线程类,一个负责读,一个负责写,同样的,服务端的代码也大同小异。


服务端:

package server_3;

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

public class server_3 {

public static final int PORT = 10000;//监听的端口号

public static void main(String[] args) {
System.out.println("sever begins");
server_3 server = new server_3();
server.init();
}

public void init() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(PORT);
while (true) {
Socket client = serverSocket.accept();
//一个客户端连接就开两个线程分别处理读和写
new Thread(new ReadHandlerThread(client)).start();
new Thread(new WriteHandlerThread(client)).start();
}
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
if(serverSocket != null){
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

/*
*处理读操作的线程
*/
class ReadHandlerThread implements Runnable{
private Socket client=null;

public ReadHandlerThread(Socket client) {
this.client = client;
}

@Override
public void run() {
BufferedReader in = null;
try{
while(true){
//读取客户端数据
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
System.out.println("客户端说:" + in.readLine());
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(client != null){
client = null;
}
}
}
}

/*
* 处理写操作的线程
*/
class WriteHandlerThread implements Runnable{
private Socket client;

public WriteHandlerThread(Socket client) {
this.client = client;
}

@Override
public void run() {
PrintWriter out=null;
try {
out = new PrintWriter(client.getOutputStream());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));//从控制台获取输入的内容
try{
while(true){
//向客户端回复信息
out.println(reader.readLine());
out.flush();
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(client != null){
client = null;
}
}
}
}

以上程序,先启动服务端,再启动客户端,就可以实现两端的任意聊天,功能和qq等软件类似。



2015年11月26日   西安交通大学