Socket
socket基于TCP/IP协议,是面向连接的,请求---->响应
服务器:ServerSocket
客户端:Socket
1.聊天室版本1
1.1 client端
public class ClientDemo1 {
public static void main(String[] args) throws Exception{
//创建客户端
Socket socket = new Socket("localhost", 8888);
//得到客户端输入流,解析出,服务端返回的数据
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
String s = dataInputStream.readUTF();
System.out.println(s);
//得到客户端输出流,将客户端信息输出到服务端
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("我是张三,您好服务端");
dataOutputStream.flush();
}
}
1.2 server端
public static void main(String[] args) throws Exception{
//创建服务端
ServerSocket serverSocket = new ServerSocket(8888);
//接收客户端连接,阻塞式,如果一个客户端连上之后,阻塞了,后面的就连不上;当有客户端连上之后,就会生成一个客户端
Socket socket = serverSocket.accept();
System.out.println("有客户端链接上了" );
//得到客户端的输出流,输出信息
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("欢迎你");
dataOutputStream.flush();
//得到客户端的输入流,输出客户端传过来的数据
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
String s = dataInputStream.readUTF();
System.out.println(s);
}
效果:
当客户端连上之后,服务端返回数据,客户端接收,然后发送数据给服务端,服务端接收
server
缺点:
1.当客户端连上服务端之后,服务端就关闭了,而且客户端数据,是固定的数据,不能达到良好的聊天效果
2.客户端只能先发送数据,然后服务端根据客户端数据返回,
2.聊天室版本2
2.1 客户端
public static void main(String[] args) throws Exception{
Socket socket = new Socket("localhost", 9999);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
while (true) {
dataOutputStream.writeUTF(bufferedReader.readLine());
dataOutputStream.flush();
//得到服务端的数据
String s = dataInputStream.readUTF();
System.out.println(s);
}
}
根据控制台输入的数据,将数据发送给服务端,使用while循环,是想可以一直输入信息和接收信息,不会关闭客户端
2.2 服务端
public static void main(String[] args) throws Exception{
ServerSocket serverSocket = new ServerSocket(9999);
//接收客户端连接,阻塞式
Socket socket = serverSocket.accept();
while (true) {
//接收客户端传来的数据
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
String s = dataInputStream.readUTF();
System.out.println(s);
//发送给客户端数据
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("欢迎你"+s);
dataOutputStream.flush();
}
}
可以一直和客户端聊天,
效果:
client server
缺点:
1.只能一个客户端连接服务端,发送信息,别的客户端连接之后,服务端不会响应
2.客户端只能先发送数据,然后服务端根据客户端数据返回,
client2
3.聊天室终极版本
需求:
聊天室中,多个客户端进行群聊,服务器进行数据的转发,
客户端进行私聊: 只需要@xxx: 想说的话, 这个信息就只能被xxx收到,如果不按这种格式发信息,就是群聊,所有人都会接受到信息
问题:
1.服务端只能有一个客户端连接
2.客户端读取和写出数据有先后顺序
改进:
1.在服务端,需要为每个客户端开辟一条线程,每个客户端之间互不影响
2.客户端,为读取和写出数据分别开辟线程,互不影响
3.1server端
public class ServerDemo3 {
List<MyChannel> myChannelList = new ArrayList<>();
public static void main(String[] args) throws Exception{
new ServerDemo3().start();
}
public void start() throws Exception{
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
//接收客户端连接,阻塞式
Socket socket = serverSocket.accept();
MyChannel myChannel = new MyChannel(socket);
myChannelList.add(myChannel);//将创建的客户端通道集中管理
new Thread(myChannel).start();//开启通道
}
}
//为每一个客户端开辟一条线程
class MyChannel implements Runnable{
private DataInputStream dataInputStream = null;
private DataOutputStream dataOutputStream =null;
private boolean isRunning = true;
private String name;//用户名称
//初始化信息
public MyChannel(Socket socket){
try {
dataInputStream = new DataInputStream(socket.getInputStream());
dataOutputStream = new DataOutputStream(socket.getOutputStream());
this.name = dataInputStream.readUTF();
send("欢迎进入聊天室");
sendOthers(name+"加入了聊天室",false);
} catch (IOException e) {
CloseUtils.CloseAll(dataInputStream,dataOutputStream);
isRunning = false;
}
}
public String recive(){
String msg = "";
try {
msg = dataInputStream.readUTF();
} catch (IOException e) {
CloseUtils.CloseAll(dataInputStream,dataOutputStream);
isRunning = false;
myChannelList.remove(this);
}
return msg;
}
/**
* 发送信息
* @param msg
*/
public void send(String msg){
try {
dataOutputStream.writeUTF(msg);
} catch (IOException e) {
isRunning = false;
CloseUtils.CloseAll(dataOutputStream,dataInputStream);
myChannelList.remove(this);
}
}
public void sendOthers(String msg,Boolean isUser){
String name = this.name;//说话的人的名字
//解析发送的数据,判断是否是私聊
if (msg.startsWith("@")&&msg.indexOf(":")>-1&&isUser){
//被@的人的名字
String username = msg.substring(1, msg.indexOf(":"));
//发送的话
String content = msg.substring(msg.indexOf(":") + 1);
for (MyChannel myChannel : myChannelList){
if (myChannel.name.equals(username)){
myChannel.send(name+"悄悄的跟你说"+content);
}
}
}else {
for (MyChannel myChannel : myChannelList) {
if (myChannel == this && isUser) {
myChannel.send("我说:" + msg);
continue;
}
if (isUser) {//如果是用户说话,把名字加上
myChannel.send(name + "说:" + msg);
}
if (!isUser) {//如果是系统公告,就直接打印
myChannel.send(msg);
}
}
}
}
@Override
public void run() {
while (isRunning){
sendOthers(recive(),true);
}
}
}
}
3.2 客户端
因为客户端要读写分离,互不影响
接受数据:
public class Recive implements Runnable {
//得到数据
private DataInputStream dataInputStream = null;
private boolean isRunning = true;
public Recive(Socket socket){
try {
dataInputStream = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
isRunning =false;
CloseUtils.CloseAll(dataInputStream);
}
}
public String recive(){
String msg ="";
try {
msg = dataInputStream.readUTF();
} catch (IOException e) {
isRunning =false;
CloseUtils.CloseAll(dataInputStream);
}
return msg;
}
@Override
public void run() {
while (isRunning){
System.out.println(recive());
}
}
}
发送数据:
public class Send implements Runnable {
private BufferedReader bufferedReader = null;
private DataOutputStream dataOutputStream = null;
private boolean isRunning = true;
private String name; //用户名称
public Send(Socket socket,String name){
try {
bufferedReader = new BufferedReader(new InputStreamReader(System.in));
dataOutputStream = new DataOutputStream(socket.getOutputStream());
this.name = name;
//当建立链接之后,发送姓名给服务端
send(name);
} catch (IOException e) {
//e.printStackTrace();
isRunning = false;
CloseUtils.CloseAll(dataOutputStream,bufferedReader);
}
}
public String getConsoleData(){
try {
return bufferedReader.readLine();
} catch (IOException e) {
isRunning = false;
CloseUtils.CloseAll(dataOutputStream,bufferedReader);
}
return "";
}
/**
* 发送信息的方法
*/
public void send(String msg){
try {
if (msg!=null && !msg.equals("")) {
dataOutputStream.writeUTF(msg);
dataOutputStream.flush();
}
} catch (IOException e) {
isRunning = false;
CloseUtils.CloseAll(dataOutputStream,bufferedReader);
}
}
@Override
public void run() {
while (isRunning){
send(getConsoleData());
}
}
}
客户端:
public static void main(String[] args) throws Exception{
Socket socket = new Socket("localhost", 8888);
System.out.println("请输入名称:");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String name = bufferedReader.readLine();//得到名称
/* BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(bufferedReader.readLine());
dataOutputStream.flush();*/
new Thread(new Send(socket,name)).start();
new Thread(new Recive(socket)).start();
}
源码:
进群交流:552113611
网友评论