JAVA中,假设一个服务器和一个客户机通信。采用UDP,我已经实现了无阻塞通信。但改成TCP就不行了。客户机和服务机只能进行一次通信,后来两者发的信息均不能到达对方的屏幕上。编程思路和用UDP协议差不多,在服务器里面,开一个线程专门发,开一个线程专门收。客户机同。不知道问题在哪。我把源码帖在下面!请有耐心的朋友帮我看下(可以调试下的)!
×××××××以下是客户机的代码:import java.io.*;
import java.net.*;
class Clientm
{
ServerSocket ss;
Socket socket;
BufferedReader br2,br1;
PrintWriter pw;
String line=null;
public Clientm()
{
try
{
//ss=new ServerSocket(9999);
socket=new Socket("127.0.0.1",9999);
br1=new BufferedReader(new InputStreamReader(System.in));
pw=new PrintWriter(socket.getOutputStream());
br2=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
public static void main(String args[])
{
Clientm cm=new Clientm();
Sendc sends1=cm.new Sendc();
Receivec receives1=cm.new Receivec();
sends1.start();
receives1.start();
}
class Sendc extends Thread //现在才知道内部类真是他妈的强大!
{
public void run()
{
try
{
line=br1.readLine();
while(!line.equals("bye"))
{
System.out.println("client is sending.....");
pw.println(line);
pw.flush();
line=br1.readLine();
}
br1.close();
br2.close();
pw.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
} class Receivec extends Thread
{
public void run()
{
try
{
System.out.println("Server Says:"+br2.readLine());
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
}×××××××××××××以下是服务器的代码
import java.io.*;
import java.net.*;
class Serverm
{
ServerSocket ss;
Socket socket;
BufferedReader br2,br1;
PrintWriter pw;
String speaking=null;
public Serverm()
{
try
{
ss=new ServerSocket(9999);
socket=ss.accept();
br1=new BufferedReader(new InputStreamReader(System.in));
pw=new PrintWriter(socket.getOutputStream());
br2=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
public static void main(String args[])
{
Serverm sm=new Serverm();
Sends sends1=sm.new Sends();
Receives receives1=sm.new Receives();
sends1.start();
receives1.start();
}
class Sends extends Thread
{
public void run()
{
try
{
speaking=br1.readLine();
while(!speaking.equals("bye"))
{
System.out.println("server is sending.....");
pw.println(speaking);
pw.flush();
speaking=br1.readLine();
}
System.out.println("connection is closed");
br1.close();
br2.close();
pw.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
} class Receives extends Thread
{
public void run()
{
try
{
System.out.println("server is receving.....");
System.out.println("Client Says:"+br2.readLine());
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
}
×××××××以下是客户机的代码:import java.io.*;
import java.net.*;
class Clientm
{
ServerSocket ss;
Socket socket;
BufferedReader br2,br1;
PrintWriter pw;
String line=null;
public Clientm()
{
try
{
//ss=new ServerSocket(9999);
socket=new Socket("127.0.0.1",9999);
br1=new BufferedReader(new InputStreamReader(System.in));
pw=new PrintWriter(socket.getOutputStream());
br2=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
public static void main(String args[])
{
Clientm cm=new Clientm();
Sendc sends1=cm.new Sendc();
Receivec receives1=cm.new Receivec();
sends1.start();
receives1.start();
}
class Sendc extends Thread //现在才知道内部类真是他妈的强大!
{
public void run()
{
try
{
line=br1.readLine();
while(!line.equals("bye"))
{
System.out.println("client is sending.....");
pw.println(line);
pw.flush();
line=br1.readLine();
}
br1.close();
br2.close();
pw.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
} class Receivec extends Thread
{
public void run()
{
try
{
System.out.println("Server Says:"+br2.readLine());
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
}×××××××××××××以下是服务器的代码
import java.io.*;
import java.net.*;
class Serverm
{
ServerSocket ss;
Socket socket;
BufferedReader br2,br1;
PrintWriter pw;
String speaking=null;
public Serverm()
{
try
{
ss=new ServerSocket(9999);
socket=ss.accept();
br1=new BufferedReader(new InputStreamReader(System.in));
pw=new PrintWriter(socket.getOutputStream());
br2=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
public static void main(String args[])
{
Serverm sm=new Serverm();
Sends sends1=sm.new Sends();
Receives receives1=sm.new Receives();
sends1.start();
receives1.start();
}
class Sends extends Thread
{
public void run()
{
try
{
speaking=br1.readLine();
while(!speaking.equals("bye"))
{
System.out.println("server is sending.....");
pw.println(speaking);
pw.flush();
speaking=br1.readLine();
}
System.out.println("connection is closed");
br1.close();
br2.close();
pw.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
} class Receives extends Thread
{
public void run()
{
try
{
System.out.println("server is receving.....");
System.out.println("Client Says:"+br2.readLine());
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
}
br1=new BufferedReader(new InputStreamReader(System.in));
pw=new PrintWriter(socket.getOutputStream());
br2=new BufferedReader(new InputStreamReader(socket.getInputStream()));
这段代码是要放到线程中去的,因为每accept一次就能从列队中读去一条信息
有必要的话去网上搜索例子代码看看就会更明白了
刚刚看了下 感觉应该 socket=ss.accept(); 要给一个循环
给个实例
import java.io.*; //引入Java.io包
import java.net.*; //引入Java.net包
import java.nio.channels.*; //引入Java.nio.channels包
import java.util.*; //引入Java.util包
public class TestServer implements Runnable{
/*** 服务器Channel对象,负责接受用户连接
*/
private ServerSocketChannel server;
/**
* Selector对象,负责监控所有的连接到服务器的网络事件的发生
*/
private Selector selector;
/**
* 总的活动连接数
*/
private int activeSockets;
/**
* 服务器Channel绑定的端口号
*/
private int port ;
/**
*
* 构造函数
*/
public TestServer()throws IOException
{
activeSockets=0;
port=9999;//初始化服务器Channel绑定的端口号为9999
selector= Selector.open();//初始化Selector对象
server=ServerSocketChannel.open();//初始化服务器Channel对象
ServerSocket socket=server.socket();//获取服务器Channel对应的//ServerSocket对象
socket.bind(new InetSocketAddress(port));//把Socket绑定到监听端口9999上
server.configureBlocking(false);//将服务器Channel设置为非阻塞模式
server.register(selector,SelectionKey.OP_ACCEPT);//将服务器Channel注册到
Selector对象,并指出服务器Channel所感兴趣的事件为可接受请求操作
}
public void run()
{
while(true)
{
try
{
/**
*应用Select机制轮循是否有用户感兴趣的新的网络事件发生,当没有* 新的网络事件发生时,此方法会阻塞,直到有新的网络事件发生为止
*/
selector.select();}
catch(IOException e)
{
continue;//当有异常发生时,继续进行循环操作
}
/**
* 得到活动的网络连接选择键的集合
*/
Set<SelectionKey> keys=selector.selectedKeys();
activeSockets=keys.size();//获取活动连接的数目
if(activeSockets==0)
{
continue;//如果连接数为0,则继续进行循环操作
}
/**/**
* 应用For—Each循环遍历整个选择键集合
*/
for(SelectionKey key :keys)
{
/**
* 如果关键字状态是为可接受,则接受连接,注册通道,以接受更多的*
事件,进行相关的服务器程序处理
*/
if(key.isAcceptable())
{
doServerSocketEvent(key);
continue;
}
/**
* 如果关键字状态为可读,则说明Channel是一个客户端的连接通道,
* 进行相应的读取客户端数据的操作
*/
if(key.isReadable())
{
doClientReadEvent(key);continue;}
/**
* 如果关键字状态为可写,则也说明Channel是一个客户端的连接通道,
* 进行相应的向客户端写数据的操作
*/
if(key.isWritable())
{
doClinetWriteEvent(key);
continue;
}
}
}
}/**
* 处理服务器事件操作
* @param key 服务器选择键对象
*/
private void doServerSocketEvent(SelectionKey key)
{
SocketChannel client=null;
try
{
ServerSocketChannel server=(ServerSocketChannel)key.channel();
client=server.accept();
if(client==null)
{
return;
}
client.configureBlocking(false);//将客户端Channel设置为非阻塞型
/**/**
* 将客户端Channel注册到Selector对象上,并且指出客户端Channel所感
* 兴趣的事件为可读和可写
*/
client.register(selector,SelectionKey.OP_READ|SelectionKey.OP_READ);
}catch(IOException e)
{
try
{
client.close();}catch(IOException e1){}
}
}
/**
* 进行向客户端写数据操作
* @param key 客户端选择键对象
*/
private void doClinetWriteEvent(SelectionKey key)
{
代码实现略;
}
/**
* 进行读取客户短数据操作
* @param key 客户端选择键对象
*/
private void doClientReadEvent(SelectionKey key)
{
代码实现略;
}
}从上面对代码可以看出,使用非阻塞性I/O进行并发型服务器程序设计分三个部分:1.
向Selector对象注册感兴趣的事件;2.从Selector中获取所感兴趣的事件;3.根据不同的事件进
行相应的处理。
结语
通过使用NIO 工具包进行并发型服务器程序设计,一个或者很少几个Socket 线程就可
以处理成千上万个活动的Socket 连接,大大降低了服务器端程序的开销;同时网络I/O 采取
非阻塞模式,线程不再在读或写时阻塞,操作系统可以更流畅的读写数据并可以更有效地向
CPU 传递数据进行处理,以便更有效地提高系统的性能
如果你要在server也实现可以读取system.in的话 那么你的client也必须去实现一个socketserver
其实你想做的是一个p2p的通讯哇 就是server是server也是client 同时client是client也是一个server
所以 在client端 你需要加一个socketserver去实现这个p2p的功能但是一般来说 不是那么写的哇 因为我觉得你的本意不是写p2p一般来说 是一个Main线程 然后再加一个Thread
Main里面一个socket.getInputStream
Thread里面一个socket.getOutStream这样就可以啦