Java多线程-----Socket通信

news/2024/7/6 6:31:13
Java多线程-----Socket通信

程序分Server和Client


服务器端打开侦听的端口,一有客户端连接就创建两个新的线程来负责这个连接

一个负责客户端发送的信息(ClientMsgCollectThread 类),

另一个负责通过该Socket发送数据(ServerMsgSendThread )

Server.java代码如下:

/*
* 创建日期 2005-7-7
*
* TODO 要更改此生成的文件的模板,请转至
* 窗口 - 首选项 - Java - 代码样式 - 代码模板
*/
package person.fane.MutiUser;

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

/**
* 服务器端
*
* @author Fane
*/
public class Server extends ServerSocket {

private static final int SERVER_PORT = 10000;

/**
* 构造方法,用于实现连接的监听
*
* @throws IOException
*/
public Server() throws IOException {
super(SERVER_PORT);

try {
while (true) {
Socket socket = super.accept();

new Thread(new ClientMsgCollectThread(socket), "getAndShow"
+ socket.getPort()).start();
new Thread(new ServerMsgSendThread(socket), "send"
+ socket.getPort()).start();

}
} catch (IOException e) {
e.printStackTrace();
}

}

public static void main(String[] args) throws IOException {
new Server();
}

/**
* 该类用于创建接收客户端发来的信息并显示的线程
*
* @author Fane
* @version 1.0.0
*/
class ClientMsgCollectThread implements Runnable {

private Socket client;

private BufferedReader in;

private StringBuffer inputStringBuffer = new StringBuffer("Hello");

/**
* 得到Socket的输入流
*
* @param s
* @throws IOException
*/
public ClientMsgCollectThread(Socket s) throws IOException {
client = s;

in = new BufferedReader(new InputStreamReader(client
.getInputStream(), "GBK"));
}

public void run() {
try {

while (!client.isClosed()) {
inputStringBuffer.delete(0, inputStringBuffer.length());
inputStringBuffer.append(in.readLine());

System.out.println(getMsg(inputStringBuffer.toString()));
}
} catch (IOException e) {
//e.printStackTrace();
System.out.println(client.toString() + " is closed!");

}
}

/**
* 构造显示的字符串
*
* @param line
* @return
*/
private String getMsg(String line) {
return client.toString() + " says:" + line;
}

}

/**
* 该类用于创建发送数据的线程
*
* @author Fane
* @version 1.0.0
*/
class ServerMsgSendThread implements Runnable {

private Socket client;

private PrintWriter out;

private BufferedReader keyboardInput;

private StringBuffer outputStringBuffer = new StringBuffer("Hello");

/**
* 得到键盘的输入流
*
* @param s
* @throws IOException
*/
public ServerMsgSendThread(Socket s) throws IOException {
client = s;

out = new PrintWriter(client.getOutputStream(), true);
keyboardInput = new BufferedReader(new InputStreamReader(System.in));

}

public void run() {
try {

while (!client.isClosed()) {
outputStringBuffer.delete(0, outputStringBuffer.length());
outputStringBuffer.append(keyboardInput.readLine());

out.println(outputStringBuffer.toString());
}
} catch (IOException e) {
//e.printStackTrace();
System.out.println(client.toString() + " is closed!");

}
}

}

}


客户端:

实现基于IP地址的连接,连接后也创建两个线程来实现信息的发送和接收

/*
* 创建日期 2005-7-7
*
*/
package person.fane.MutiUser;

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

/**
* 客户端
*
* @author Fane
*/
public class Client {

private Socket mySocket;

/**
* 创建线程的构造方法
*
* @param IP
* @throws IOException
*/
public Client(String IP) throws IOException {

try {
mySocket = new Socket(IP, 10000);
new Thread(new ServerMsgCollectThread(mySocket), "getAndShow"
+ mySocket.getPort()).start();
new Thread(new ClientMsgSendThread(mySocket), "send"
+ mySocket.getPort()).start();

} catch (IOException e) {
//e.printStackTrace();
System.out.println("Server.IP:" + IP
+ " port:10000 can not be Connected");
}
}

public static void main(String[] args) throws IOException {
try {
new Client(args[0]);
} catch (Exception e) {
System.out.println("输入的IP地址错误");
}
}

/**
* 该类用于创建接收服务端发来的信息并显示的线程
*
* @author Fane
* @version 1.0.0
*/
class ServerMsgCollectThread implements Runnable {

private Socket client;

private BufferedReader in;

private StringBuffer inputStringBuffer = new StringBuffer("Hello");

/**
* 得到Socket的输入流
*
* @param s
* @throws IOException
*/
public ServerMsgCollectThread(Socket s) throws IOException {
client = s;

in = new BufferedReader(new InputStreamReader(client
.getInputStream(), "GBK"));
}

public void run() {
try {

while (!client.isClosed()) {
inputStringBuffer.delete(0, inputStringBuffer.length());
inputStringBuffer.append(in.readLine());
System.out.println(getMsg(inputStringBuffer.toString()));
}
} catch (IOException e) {
//e.printStackTrace();
System.out.println(client.toString() + " is closed!");
System.exit(0);
}
}

/**
* 构造输入字符串
*
* @param line
* @return
*/
private String getMsg(String line) {
return client.toString() + " says:" + line;
}

}

/**
* 该类用于创建发送数据的线程
*
* @author Fane
* @version 1.0.0
*/
class ClientMsgSendThread implements Runnable {

private Socket client;

private PrintWriter out;

private BufferedReader keyboardInput;

private StringBuffer outputStringBuffer = new StringBuffer("Hello");

/**
* 得到键盘的输入流
*
* @param s
* @throws IOException
*/
public ClientMsgSendThread(Socket s) throws IOException {
client = s;

out = new PrintWriter(client.getOutputStream(), true);
keyboardInput = new BufferedReader(new InputStreamReader(System.in));

}

public void run() {
try {

while (!client.isClosed()) {
outputStringBuffer.delete(0, outputStringBuffer.length());
outputStringBuffer.append(keyboardInput.readLine());

out.println(outputStringBuffer.toString());
}
out.println("--- See you, bye! ---");
} catch (IOException e) {
//e.printStackTrace();
System.out.println(client.toString() + " is closed!");
System.exit(0);
}
}

}

}



该程序基本通信没有问题

但是有如下bug,请各位提出宝贵意见

1:在cmd模式下,用Ctrl+C来结束客户端程序,服务器先出现收到为null,再出现断开连接的提示,在直接关闭命令行时就只提示断开连接,不知道这个null何来

Socket[addr=/192.168.0.12,port=2205,localport=10000] says:null
Socket[addr=/192.168.0.12,port=2205,localport=10000] is closed!

2:假如打开5个命令行并连接成功后,发送信息时,服务器能收到所有5个客户端来的信息,但是5个客户端只能轮流收到服务器的信息,也就是说我每打一个"Hello"+Enter,只有一个客户端能收到消息,重复5次,这样每个客户端都能收到一次,这个本不奇怪(设计的问题,不好意思),但是我关闭了其中4个以后,还是要发5次客户端才能收到一次消息,也就是说其他4个Socket关闭了,但是线程没有关闭,不知道怎样才能解决线程的这个问题(在一台机子上试验出现这个问题)

发送:

Socket[addr=/192.168.0.12,port=2201,localport=10000] is closed!
Socket[addr=/192.168.0.12,port=2203,localport=10000] says:null
Socket[addr=/192.168.0.12,port=2203,localport=10000] is closed!
Socket[addr=/192.168.0.12,port=2204,localport=10000] says:null
Socket[addr=/192.168.0.12,port=2204,localport=10000] is closed!
Socket[addr=/192.168.0.12,port=2205,localport=10000] says:null
Socket[addr=/192.168.0.12,port=2205,localport=10000] is closed!

hehhe
hehe
hehe
hehe
hehe

接收:Socket[addr=/192.168.0.12,port=10000,localport=2206] says:hehe

(前面4个hehe丢失了)

其它bug也在查找中.......

http://www.niftyadmin.cn/n/3855206.html

相关文章

算法学习-哈希表

之前在大学学习数据结构的时候,学过数组和链表。数组的优点就是可以直接定位,速度快,但是缺点就是插入删除,效率就慢了很多。链表的可以快速的插入删除,但是不能直接定位,需要遍历才可以。他们使用在不同的…

改变VM内存大小

-Xms512m -Xmx1024m -XX:PermSize128M -XX:MaxPermSize256M 转载于:https://blog.51cto.com/yaomingkai/1125760

数据库如何处理多对多的关系

数据库设计多对多关系的几种形态(7种) Posted on 2009-06-09 23:37 peterzb 阅读(739) 评论(1) 编辑 收藏 所属分类: 数据库技术数据库设计多对多关系的几种形态 前言:多对多关系至少需要3个表,我们把一个表叫做主表,一…

iOS: Device token and registerForRemoteNotificationTypes, didReceiveRemoteNotification

分类: Mobile iOS2012-04-18 19:25 244人阅读 评论(0) 收藏 举报Device token for an iPhone device生成之后就永远不变吗? 不是,if a device is wiped (应该是重装系统), it will get a new device token. 官方网站是这样写的: …

Java纯POJO类反射到Redis,反射到MySQL

这个是类定义&#xff0c;都是POJO类&#xff0c;纯数据 以下代码将POJO类反射到REDIS中&#xff0c;采用JSON序列化类数据。 public static <T> T save(T model, String indexName) throws Exception {String modelName model.getClass().getSimpleName();Jedis jedis …

PowerDesigner建模工具

PowerDesignerPowerDesigner建模工具 PowerDesigner是Sybase公司的CASE工具集&#xff0c;使用它可以方便地对管理信息系统进行分析设计&#xff0c;它几乎包括了数据库模型设计的全过程。 利用PowerDesigner可以制作数据流程图、概念数据模型、物理数据模型&#xff0c;可以生…

管理时间是空话,集中精力吃青蛙

别再想着管理时间了。找出你一天、一周、一个月、一年、一生中最重要的三件事&#xff0c;它们就是你必须吃掉的“三只青蛙”。 利用帕累托定律&#xff0c;每天划出20%的时间&#xff0c;集中精力&#xff0c;专门对付这三只青蛙。 坚持不懈&#xff0c;你的人生就能取得完全不…

VirtualBox修改UUID实现VM复制

virtualbox是一个很好用的虚拟机软件&#xff0c;可以和VmWare想媲美。缺点也有&#xff0c;就是对CPU虚拟的功能不强。 我用VirtualBox做了一个Ubuntu Server虚拟镜像。我想实现复制几个&#xff0c;然后可以同时装载几个虚拟机。 但是在我想把复制的镜像载入的时候&#xff0…