简单的java socket通信,多个客户端同时连接,功能可在此基础上进行扩展。效果如图:
server:
package com.lb.LB_Socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class myServer {
private ServerSocket server;
private Socket socket;
private BufferedReader brin;
private PrintWriter pw;
private BufferedReader in ;
private Boolean bool=true;
public static void main(String args[]){
myServer ms = new myServer();
try {
ms.onServer();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void onServer() throws IOException{
try{
try{
server = new ServerSocket(4440);
System.out.println("服务器已启动!");
}catch(Exception e){
System.out.println("服务器未启动:"+e);
}
while(true){
try{
socket = server.accept();
System.out.println("客户端接入--");
bool=true;
}catch(Exception e){
System.out.println("出错了 :"+e);
}
while(bool){
brin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw= new PrintWriter(socket.getOutputStream());
in= new BufferedReader(new InputStreamReader(System.in));
String content = brin.readLine();
System.out.println("客户端:"+content);
if(content.equals("exit")){
pw.println("欢迎下次再来!");
pw.flush();
System.out.println("客户端退出!");
bool=false;
}
/*
String replay = in.readLine();
pw.println(replay);
pw.flush();
*/
}
}
}catch(Exception e){
System.out.println("Error:"+e);
}finally{
if(pw!=null){
pw.close();
}
if(brin!=null){
brin.close();
}
if(in!=null){
in.close();
}
if(socket!=null){
socket.close();
}
if(server!=null){
server.close();
}
}
}
}
服务器端(ServerSocket):使用while()死循环一直等待客户端的连接,在使用while(bool)循环接收客户端发送来的数据,如果客户端退出则等待下一个客户机的连接,
客户端:
package com.lb.LB_Socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
public class myClient implements Runnable{
private Socket socket;
private BufferedReader brin;
private PrintWriter pw;
private BufferedReader in ;
private Boolean bool = true;
public static void main(String args[]) throws IOException{
new Thread(new myClient()).start();
}
@Override
public void run() {
// TODO Auto-generated method stub
try{
socket = new Socket("192.168.30.36",4440);
System.out.println("客户端启动成功!");
try{
while(bool){
in = new BufferedReader(new InputStreamReader(System.in));
pw = new PrintWriter(socket.getOutputStream());
brin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String readline;
readline = in.readLine();
//System.out.println(readline);
pw.println(readline);
pw.flush();
if(readline.equals("exit")){
in.close();
pw.close();
brin.close();
socket.close();
bool = false;
}
//System.out.println("服务器:"+brin.readLine()); //服务器回复
}
}catch(SocketException e){
if(socket==null){
System.out.println("断开连接!");
}
}catch(Exception e){
e.printStackTrace();
System.out.println("未开启服务器");
}
}catch(Exception e){
e.printStackTrace();
}
}
}
客户端(Socket):发送数据,使用while()循环当客户机在线时连续发送消息,发送exit时,销毁对象,退出连接。
想实现无阻塞通信,双端随时发送消息,但基本的socket通信就是你发一句我发一句,我发了你不发,我这边就处于等待接收状态,也就是阻塞。
- 就是利用线程,接收和发送是两个线程,互不干扰,随发随收;待实践。
- 非阻塞的通信机制。服务器程序接收客户连接、客户程序建立与服务器的连接,以及服务器程序和客户程序收发数据的操作都可以按非阻塞的方式进行。服务器程序只需要创建一个线程,就能完成同时与多个客户通信的任务。非阻塞的通信机制主要由java.nio包(新I/O包)中的类实现,主要的类包括ServerSocketChannel、SocketChannel、Selector、SelectionKey和ByteBuffer等。
初步实现利用线程解决非阻塞通信
看下效果:
基本的想法就是把发送消息和接收打印消息作为单独的线程启动。直接贴代码了
sendMsg:
package com.lb.LB_Socket;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class sendMsg implements Runnable {
private DataOutputStream dos = null;
//private DataInputStream dis = null;
private Socket socket = null;
private BufferedReader br =null ;
private String name;
private String content;
boolean bool = true;
public sendMsg(Socket socket,String name){
//super();
this.socket = socket;
this.name = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(bool){
try {
dos = new DataOutputStream(socket.getOutputStream());
br = new BufferedReader(new InputStreamReader(System.in));
content = br.readLine();
dos.writeUTF(name+"说:"+content);
if(content.equals("exit")){
dos.close();
br.close();
socket.close();
bool = false;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
bool=false;
}
}
}
}
printMsg:
package com.lb.LB_Socket;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class printMsg implements Runnable {
//private DataOutputStream dos = null;
private DataInputStream dis = null;
private Socket socket = null;
private String content;
boolean bool = true;
//private String name;
public printMsg(Socket socket){
//super();
this.socket = socket;
//this.name = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(bool){
try {
dis = new DataInputStream(socket.getInputStream());
content = dis.readUTF();
System.out.println(content);
} catch (IOException e) {
// TODO Auto-generated catch block
bool=false;
e.printStackTrace();
//System.exit(1);
}catch(Exception e){
bool = false;
e.printStackTrace();
}
}
}
}
server:
package com.lb.LB_Socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class myServer implements Runnable{
private boolean bool=true;
Socket socket = null;
ServerSocket server= null;
public static void main(String args[]){
new Thread(new myServer()).start();
}
@Override
public void run() {
// TODO Auto-generated method stub
try{
try{
server = new ServerSocket(4440);
System.out.println("服务器已启动!");
}catch(Exception e){
System.out.println("服务器未启动:"+e);
}
while(true){
try{
socket = server.accept();
System.out.println("客户端接入--");
bool=true;
}catch(Exception e){
System.out.println("出错了 :"+e);
}
sendMsg send = new sendMsg(socket,"服务器");
printMsg print = new printMsg(socket);
Thread s= new Thread(send);
Thread p = new Thread(print);
if(send.bool == false || print.bool==false){
s.interrupt();
p.interrupt();
}else{
s.start();
p.start();
}
}
}catch(Exception e){
System.out.println("Error:"+e);
}finally{
try{
if(socket!=null){
socket.close();
}
if(server!=null){
server.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
client:
package com.lb.LB_Socket;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class myClient{
public static void main(String args[]){
try {
Socket socket = new Socket("192.168.30.36",4440);
System.out.println("客户端启动成功!");
sendMsg send = new sendMsg(socket,"客户");
printMsg print = new printMsg(socket);
Thread s= new Thread(send);
Thread p = new Thread(print);
if(send.bool == false || print.bool==false){
p.interrupt();
s.interrupt();
}else{
s.start();
p.start();
}
//System.out.println(socket.isConnected());
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
问题是线程的控制,当成功连接以后,互发消息,当某一方断掉后,线程就会打印错误。
1. 断掉客户端,服务端起的发送、接收流线程无法判定关闭,导致下次客户端连接后,会出现短暂的接收不到消息及错误信息打印。之后恢复正常。
2. 断掉服务器,客户端的发送、接收流线程无法判定关闭退出,打印连接错误信息。
如何控制socket的连接,监听socket连接的状态以供事件处理、关闭流。
还需多多学习,东西真的太多了。