这篇文章将使用java的socket通讯完成一个多人聊天以及文件传输的例子。这里例子中聊天和文件传输可以同时进行。
当然两者都是基于TCP协议的,因为无论是聊天还是文件传输要保证数据的完整性,如果是使用UDP,数据传输将会不可靠。
至于两者的区别也就不多说了,不懂得稍微百度一下咯。
基于socket通讯的知识在大学的时候学过了,那时是使用c/c++语言完成的,实现起来要比java稍微复杂一点。那时候聊天和,传输文件可没有这么简单,我记得写聊天系统的时候,我们还要自定义协议!现在java帮我们封装了很多方法,使用起来就方便多了。话不多说,下面准备开始丢代码:
socket通讯,我们写例子一般是客户端和服务器进行通讯,那在java中,就有两个类需要注意
1.ServerSocket : 顾名思义,这就是用来建立服务器端套接字的,除了构造方法,它主要的方法有
bind():用来绑定一个ip地址,如果不调用这个方法,则默认是本机ip
accept():监听客户端的链接,这方法一直阻塞,直到有客户端链接,然后得到该客户端的套接字
close():关闭套接字
2.socket :套接字,这个客户端发起链接需要的。获取到套接字就能进去通讯了,它除了构造方法之外主要的方法:
connect():通常用于客户端发起TCP连接。
getInputStream():获取输入流,这个可重要了,就是获取对方给你传输的数据流
getOutputStream():获取输出流,一样重压力,用于给对方传输数据
close():关闭套接字
这都是常用的几个方法,其他方法大家自己去了解吧。
多人聊天
首先我们需要先写个服务器,代码如下:
package server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
public static void main(String[] args) {
initServer();
}
private static void initServer() {
ServerSocket ss = null;
try {
ss = new ServerSocket(5001);
System.out.println("服务器正在运行...");
for (;;) {
Socket client = ss.accept();
System.out.println("新客户端链接:" + client.getPort());
new SocketThread(client).onStart();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
static class SocketThread extends Thread {
private Socket socket;
private boolean flag = true;
public SocketThread(Socket socket) {
this.socket = socket;
}
public void onStart() {
this.start();
}
@Override
public void run() {
System.out.println("链接成功!");
BufferedReader reader = null;
BufferedWriter writer = null;
try {
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
while (flag) {
String content = reader.readLine();
if (content == null || content.equals("bye")) {
flag = false;
System.out.println(socket.getPort() + "已经断开链接");
} else {
System.out.println("收到消息:" + content);
/*writer.write("我收到了您的消息! 在" + System.currentTimeMillis());
writer.flush();*/
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(socket.getPort() + "已经断开链接");
flag = false;
} finally {
try {
reader.close();
writer.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
这里的服务器没有实现多人转发的逻辑,如果要实现类似于QQ的群聊,每个人发的消息都能看到,就在收到消息的逻辑里面实现转发就行了。
这里我就不写了,大致逻辑就是,用一个map保存所有已经链接客户端,一旦有用户发消息到服务器,服务器就转发到所有已经链接的客户端。
为什么我用map,好处就是,一旦某个用户断开连接,我们可以根据key值把它删除掉