问题描述
刚学了Socket编程,想拓展一下.与连接池一起用.增加其可用性.自己写了下,运行没得到想要的结果.不知道错在哪里,所以只能请各位帮忙了.Server端:package pool;import java.net.ServerSocket;import java.net.Socket;public class Server implements Runnable{protected static int maxLeng;private static int port;private static ServerSocket server;public Server() {}public Server(int port,int maxLength){this.port=port;this.maxLeng=maxLength;}public void run(){try {server=new ServerSocket(port,maxLeng);//创建一个最大链接次数为5次的ServerSocket.Socket socket=server.accept();pool.addSocket(socket);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {Server server=new Server(9090,5);server.run();}}pool and cilent:package pool;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;import java.util.LinkedList;import java.util.List;public class pool implements Runnable{ private static List poolList=new LinkedList(); private Socket socket; private String ip; private int port; public pool() {// TODO Auto-generated constructor stub} public pool(String ip,int port){ this.ip=ip; this.port=port; } public static void addSocket(Socket socket){ synchronized (poolList) {//将连接池同步起来poolList.add(poolList.size(),socket);poolList.notifyAll();} } public void make(){ try {socket=new Socket(ip,port);File file=new File("e:\我的工号.txt");BufferedReader read=new BufferedReader(new InputStreamReader(new FileInputStream(file)));String tempStr="";String temp=null;PrintWriter pw=new PrintWriter(socket.getOutputStream());while((temp=read.readLine())!=null){tempStr+=(temp+"r");}pw.write(tempStr);pw.close();read.close();} catch (Exception e) {e.printStackTrace();} }public void run() {while(true){synchronized (poolList) {while(poolList.isEmpty()){try {poolList.wait();} catch (InterruptedException e) {return;}}Socket socket=(Socket)poolList.remove(0);}make();}} public static void main(String[] args) {add();}public static void add(){for(int i=0;i<Server.maxLeng;i++){pool p=new pool("10.43.9.51",9090);new Thread(p,i+"").start();}}}本来是希望通过Socket多线程的读文件.现在运行出现的结果没有报错.也没有任何内容输出.(注:操作步骤没有问题的.) 问题补充:Rainbow702 写道
解决方案
引用还有个地方。 socket=(Socket)list.remove(0);这句话是什么意思。看上去很诡异,不是删除掉list中的第一个值么,为什么还有返回值呢.哦..是不是说进入同步的这个线程要占用这个链接资源,所以要将该资源从list里面去掉啊. 对 这个方法就是从列表删除了第一个对象,并且把这个对象返回出去。删除的意思就是 想从连接池中去掉这个,标识已经被占用了。欢迎采纳! 不懂的可以站内问我。
解决方案二:
兄弟,我有点凌乱了,你的 pool 类中的 addPoolObject() 在哪被调用的呢?
解决方案三:
引用我把这句注释了。好像也不影响。这句话到底是什么作用呢。 我查了下。remove在这里是每删除一个元素.其他的元素索引都会向前移动. 在这里为什么要这样写呢. 其实不这么写也可以,直接删除,只是说有的被删除元素假如里面的属性对你还有用的话,就可以继续引用啊。
解决方案四:
引用是不是说进入同步的这个线程要占用这个链接资源,所以要将该资源从list里面去掉啊并不是啊,如果说你下面不调用 readFie()的话,你就没有必要从 list 里面移除socket了
解决方案五:
引用socket=(Socket)list.remove(0)你可以去看一下 list 的 remove() 方法的说明,它的确是把一个元素从这个 list 移除了,但它同时还把这个移除的元素给返回了
解决方案六:
引用哦。。好像明白了。ServerSocket的链接个数,跟连接池是不一样的。 嗯,服务端不会自动给你创建空闲连接等你来用的,而是连上一个客户端就开启一个连接。如果还有疑问,我们继续交流,希望对你有用,同时欢迎兄弟采纳啊。
解决方案七:
但是客户端socket可以有无数个,而且都是有ip地址的,所以你不可能最开始都生成一大堆客户端socket,然后给客户用,不能这样。好啦 欢迎lz采纳我的意见,谢谢。
解决方案八:
引用哦。。好像明白了。ServerSocket的链接个数,跟连接池是不一样的。 肯定是不一样的,serverSocket就相当于一个服务器,你只需要一个在不停的accept就行了。就比如tomcat,它底层其实就是启动一个serverSocket在不断的等待。
解决方案九:
引用那也就是说服务端启动的时候,在连接池中放如了5个正在等待的链接,对么。不是这样理解的。而应该这么理解,你的ServerSocket 不是指定了上限了么,那么你的while(true) { socket.accept();}应该最多只允许五个客户端连接它,超过五个的话,可能是让客户端等待,直到有客户端断开已知连接
解决方案十:
引用那就应该是在连接池里面创建新的链接咯。怎么创建呢。好像还得有状态的标明的引用你的意思是这里同步的应该是一个Socket对象么 1,也就是说你创建socket连接池这个想法从根本上就是错误的。2,我的意思就是 Object obj=new Object();然后synchronized(obj){}
解决方案十一:
引用这句话也没看懂。对象锁与业务相关是什么意思呀。怎么样才是与业务相关呢。举个例子说明一下吧。你现在synchronized(list)你的list是缓存连接的,是有特殊用处的,就相当于与业务有关了我是说单独Object obj=new Object();然后synchronized(obj)。
解决方案十二:
引用上面那个是在启动服务端的时候,创建的连接池,这个时候客户端还没有链接服务端的。 如果你只是启动了Server,当然还是没有用的啊。你必须启动:① server ② pool ③ test ,且顺序不能改变
解决方案十三:
引用没看懂。还是不明白。如果客户端有100个请求,但服务端值允许5个,该怎么样写才能使服务端请求不够用的情况下,自动创建新的链接呢。 你的理解其实是错的。特别是 “自动创建新的链接呢”这句话。这个和数据库连接不一样。你服务器接收连接 虽然可以限制个数,但是你在服务端不能创建多个连接,放在这里等你客户端用。因为像这样的socket,是需要客户端连接后才能产生的,是标识有具体ip的套接字。而数据库连接不一样,它不用标识你是哪里来的,只要给出用户名密码,所有创建的连接都是一样的,所以才可以缓存到list里面供给你使用。
解决方案十四:
等你的 Test 类中客户端与 服务端的 Socket 连通的时候,服务端就把这个 socket 通过 pool 的 addPoolObject() 添加到了 list 中,然后 list.notifyAll() 就唤醒了 pool 所在的线程,使得 list.wait(); 完成了使命,继而执行它下面的代码
解决方案十五:
还有你的对象锁最好与业务有关,不要用list来当对象锁。假如这个对象在另外地方被其他线程引用,同样会造成死锁。
解决方案:
引用//////这里有点不明白.启动服务端的时候调用pool的线程.是为了初始化一个连接池么,pool类中run方法,list刚开始也是没有值的,为什么不会产生死锁一直等待呢. 因为你把发送请求至服务端以连接Socket的代码socket=new Socket(ip,port); 放到了 Test 类中了啊,它与你的 pool 类是没有关系的,当然就可以启动了
解决方案:
引用这里有点不明白.启动服务端的时候调用pool的线程.是为了初始化一个连接池么,pool类中run方法,list刚开始也是没有值的,为什么不会产生死锁一直等待呢. 因为虽然是空的,但是这个是多线程,另外的线程已经加了之后,会让把wait的线程锁改成notifyAll()的状态。
解决方案:
引用貌似会一直等待。。。 就是我上面说的那个死循环
解决方案:
还有,你的连接池的逻辑感觉有问题啊,一般是初始化一些连接进去,然后在empty的时候,你不光的等待,你得填充你的连接池啊,不然就一直等待了
解决方案:
引用while换成if然后后面加一个else{this.notifyAll();} 没用的,根本不会走到这个else中去
解决方案:
引用各位稍等。容我在把代码规范一下。分开写。。 好 写好了 我在我本机改改。
解决方案:
你这个整体得改啊 从哪里说哦
解决方案:
建议分成三个部份来写:① 服务端② 客户端③ 连接池
解决方案:
while换成if然后后面加一个else{this.notifyAll();}试试。
解决方案:
引用为什么会走不到make()方法呢.哪里有问题么 因为你在调用 make() 之前,有这么一段synchronized (poolList) {while(poolList.isEmpty()){try {poolList.wait();} catch (InterruptedException e) {return;}}Socket socket=(Socket)poolList.remove(0);} 首先,其中的 poolList.wait();它会被执行,然后就一直阻塞在这个地方,而后,你的服务端一直在等待一个客户端来与它进行连接(因为 accept() 是阻塞的),这样的话,服务端无法与任何一个客户端进行连接,也就无法执行pool.addSocket(socket); ,这样就相当陷入一个死循环:服务在等客户端进行连接,而且客户端在等服务端产生的 socket。
解决方案:
synchronized (poolList) { while(poolList.isEmpty()){ try { poolList.wait(); } catch (InterruptedException e) { return; } 这段话,当线程进入之后,假如遇到empty的时候这个线程wait,等于是这个线程等待在这里,然后让别的线程进入,但是假如别的线程也等着了,那么没有唤醒程序了,所以互相锁住就死锁啦。
解决方案:
socket 编程真是一个好东西了。来学习下。
解决方案:
public static void main(String[] args) { Server server=new Server(9090,5); server.run(); } } 这段代码有问题,你应该这样做:public static void main(String[] args) { Server server=new Server(9090,5); Thread threadServer=new Thread(server);threadServer.start(); } }而不是直接调用run方法。
解决方案:
那你的 make() 在什么情况才会调用到呢?是在你 pool 类的run方法的最后面,但你的这个 run() 方法什么时候可以走到调用 make() 的这段代码呢?走不到。
解决方案:
引用pool.addSocket(socket);服务器在监听了,但是你有客户端往服务端发送连接请求么?