读书人

Socket菜鸟提问

发布时间: 2013-12-04 17:21:02 作者: rapoo

Socket初学者提问
-------------
首先声明:
我在控制台上编程,
目的:
能够使得SocketTest(客户端)和ClientTest(服务端)互相通信
自己判断:
SocketTest可以单独和telnet通信,所以问题锁定在ClientTest上!
-------------
请看代码:


import java.net.* ;
import java.util.* ;
import java.io.* ;
public class ClientTest{
public static void main(String[]args){
long start = System.currentTimeMillis() ;
start() ;
long end = System.currentTimeMillis() ;
System.out.println("总共连接时间:"+(end-start)+"(ms)") ;
}
public static void start(){
try{
Socket s = new Socket() ;
try{
s.connect(new InetSocketAddress("127.0.0.1",9000),10000);//连接不得超过10秒钟
OutputStream out = s.getOutputStream();
InputStream in = s.getInputStream () ;

boolean done = false ;
while(!done)
{
Scanner serverSay = new Scanner(in);
String line = "" ;
/***
* 目的:一开启Client,就先尝试接收服务端发过来的信息
* 问题:运行程序,并未接到SocketTest服务端传来的提示信息,
* 我自己调试,发现貌似出现了阻塞,hasNextLine()阻塞了,
* 导致接收不到数据,但我不知道怎么改?
*/
while( serverSay.hasNextLine() ){
line = serverSay.nextLine() ;
System.out.println(line);
}

System.out.print("我说 : ") ;
String iStr = consoleRead(null) ; //说话的内容
byte[] serverSayBytes = iStr.getBytes(); //把数据组成字节流
out.write(serverSayBytes) ; //发送数据
out.flush();
}// end while
}//end try
finally{
s.close() ;
}
}//end try
catch(Exception err){
err.printStackTrace() ;
}
}
/**
* @param: 在输入控制台之前,控制台出现的提示语
* @return:在控制台输入的语句,以'!'、'!'、'\n'结束
*/
public static String consoleRead(String prompt/*输入控制台前,控制台的提示语*/)
throws IOException{
if( null != prompt )
System.out.println(prompt);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine() ;
return str ;
}
}

-------------
再次声明:
我在控制台上编程,
目的:
能够使得SocketTest(客户端)和ClientTest(服务端)互相通信
自己判断:
SocketTest可以单独和telnet通信,所以问题锁定在ClientTest上!
-------------
【服务端代码,我自己放在1楼,不然问题太长大家不愿看】

提问:
问题1:
请各位看看问题的ClientTest.java第30行,上面的注释提出了问题。

问题2:
如果把30行开始的代码
while( serverSay.hasNextLine() ){
line = serverSay.nextLine() ;
System.out.println(line);
}
改成:
//while( serverSay.hasNextLine() ){
line = serverSay.nextLine() ;
System.out.println(line);
//}
就能接到SocketTest数据,虽然只能接到一条数据,
但是,写完数据后,却无法发送回服务端SocketTest,非要Ctrl+C关闭程序时才能发送数据!
我推测是写的数据被放进了BUF缓存,可是我都out.flush()了?
所以,依然不解 ... 求指教
【服务端代码,我自己放在1楼,不然问题太长大家不愿看】
[解决办法]
下面是现实客户端给服务端发送信息,并在服务端显示出来(用Eclipse)
服务端

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class ServerTread extends Thread
{
private Socket socket;

public ServerTread(Socket socket)
{
this.socket = socket;
}

@Override
public void run()
{
try
{


InputStream is = socket.getInputStream();

while (true)
{
byte[] b = new byte[1024];

int length = is.read(b);

String str = new String(b,0,length);

System.out.println(str);
}
}
catch (IOException e)
{
e.printStackTrace();
}


}
}



客户端

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

public class ClientTread extends Thread
{
private Socket socket;

public ClientTread(Socket socket)
{
this.socket = socket;
}

@Override
public void run()
{
try
{
OutputStream out = socket.getOutputStream();

while (true)
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

String line = br.readLine();

out.write(line.getBytes());
}
}
catch (IOException e)
{
e.printStackTrace();
}

}

}



服务端测试类

import java.net.ServerSocket;
import java.net.Socket;

public class ServerTest
{
public static void main(String[] args) throws Exception
{
ServerSocket serverSocket = new ServerSocket(5000);

while (true)
{
Socket socket = serverSocket.accept();

new ServerTread(socket).start();
}
}
}


客户端测试类

import java.net.Socket;

public class ClientTest
{
public static void main(String[] args) throws Exception
{
Socket socket = new Socket("127.0.0.1", 5000);

new ClientTread(socket).start();
}
}


[解决办法]
这里有个socket的例子,你可以看看:
http://kanpiaoxue.iteye.com/admin/blogs/1956800
[解决办法]
引用:
Quote: 引用:

这里有个socket的例子,你可以看看:
http://kanpiaoxue.iteye.com/admin/blogs/1956800


你好,你这里有好多文章,看哪一篇呢 ?


java net 编程(Socket,netty)
[解决办法]
引用:
Quote: 引用:

Quote: 引用:

Quote: 引用:

这里有个socket的例子,你可以看看:
http://kanpiaoxue.iteye.com/admin/blogs/1956800


你好,你这里有好多文章,看哪一篇呢 ?


java net 编程(Socket,netty)


可是我的代码错在哪里呢?
我的2个问题就在那 ...
可是真心不懂了!

不是都说OuputStream负责发送,InputStream负责接受么?
那么我用Scanner(InputStream )后,scanner.hasNextLine()为什么就接收不了所有的?何况我还flush了。
为什么我的OutputStream无法发送,非要关闭程序才发送?

我希望你能指点我一下 ... 可以么?


你的具体的代码我没看。不过看了你的问题的描述,推测如下:
你的服务器端的 OuputStream write数据的时候,在里面添加\n了么?
因为你的clietn像是readLine()读取的数据,他需要\n来表示新的一行。
同时,你的client端发送数据给Server的时候,如果server也是用的readLine(),那么你client发送数据的时候,也需要添加\n来结尾,表示你的发送一个line已经结束。
为啥会阻塞?应该就是你没有添加\n,造成你的程序认为读取的流文件没有结束,而继续等待。
[解决办法]

while( serverSay.hasNextLine() ){
line = serverSay.nextLine() ;
System.out.println(line);
}

System.out.print("我说 : ") ;

也就是说你的“我说 :”没有执行,依然阻塞在 serverSay.hasNextLine() 这里。问题的地方都找到了,原因应该也就出来了。看你的服务器输出,应该是你的服务器输出有问题,造成serverSay.hasNextLine()没结束,依然在等待。
解决这种client和server的通讯的关键在于:协议的一致性。比如client和server都采用\n表示内容的结束,都采用readline读取数据。这样协议是一致的,就不会出现你这种阻塞的问题。阻塞?为什么呢?就是通讯的协议不一致。
[解决办法]

OutputStream outStream = incoming.getOutputStream();
InputStream inStream = incoming.getInputStream();
outStream.write("Hello ! Enter BYE to exit .\n".getBytes());
outStream.write("me[c]:\n".getBytes());

outStream.flush();//添加这行代码

[解决办法]
我觉得你应该把 InputStream in = s.getInputStream () ;写进循环中,因为这行代码,他只能发送一次!再次发送语句的话,你应该在写这样的一个语句!在服务器那端也一样
[解决办法]
上面的代码有些问题,我做了一下调整,如下:



import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

/**
* <pre>
* @author kanpiaoxue
* Date 2013-11-27
* </pre>
*/
public class TalkSocketServer {
private static final Logger LOGGER = Logger
.getLogger(TalkSocketServer.class);

class Producer implements Runnable {
private BlockingQueue<Socket> queue;
private ServerSocket server;

public Producer(String name, BlockingQueue<Socket> queue, int port) {
super();
this.queue = queue;
try {
Thread.currentThread().setName(name);
server = new ServerSocket(port);
} catch (IOException e) {
LOGGER.error("Error:" + e.getMessage(), e);
}
}

@Override
public void run() {
LOGGER.info(server + " start to work.");
while (true) {
try {
queue.put(server.accept());
} catch (Exception e) {
LOGGER.error("Error:" + e.getMessage(), e);
}
}

}
}

class Consumer implements Runnable {

private BlockingQueue<Socket> queue;

public Consumer(String name, BlockingQueue<Socket> queue) {
super();
this.queue = queue;
Thread.currentThread().setName(name);
}

@Override
public void run() {
while (true) {
Socket socket = null;
try {
socket = queue.take();
consume(socket);
} catch (Exception e) {
LOGGER.error("Error:" + e.getMessage(), e);
} finally {
if (null != socket) {
try {
socket.close();
LOGGER.info(socket + " closed.");
} catch (IOException e) {
}
}
}
}

}

private void consume(Socket socket) throws Exception {
PrintWriter writer = new PrintWriter(socket.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
sendMsg(writer, "Welcome to talking system!");
for (String request = reader.readLine(); null != request; request = reader
.readLine()) {
if (request.trim().equalsIgnoreCase("bye")) {
sendMsg(writer, "Good bye " + socket + " !");
closeAll(writer, reader, socket);
break;
}
sendMsg(writer, socket + "You say [" + request + "] to me.");
}

// close all resource
closeAll(writer, reader, socket);
}

private void closeAll(Writer writer, Reader reader, Socket socket)
throws IOException {
IOUtils.closeQuietly(writer);
IOUtils.closeQuietly(reader);
socket.close();
}

private void sendMsg(PrintWriter writer, String msg) {
writer.println(msg);
writer.flush();
}
}

/**
* @param args
*/
public static void main(String[] args) {
TalkSocketServer t = new TalkSocketServer();
ExecutorService exec = Executors.newCachedThreadPool();
BlockingQueue<Socket> queue = new LinkedBlockingQueue<Socket>();
int port = 7777;
exec.execute(t.new Producer("producer", queue, port));
for (int i = 0, j = Runtime.getRuntime().availableProcessors() * 2; i < j; i++) {
exec.execute(t.new Consumer("consumer-" + i, queue));
}
exec.shutdown();
}

}


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

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

/**
*
* @author kanpiaoxue
*
*/
public class TestSocketClient {
private static final Logger LOGGER = Logger
.getLogger(TestSocketClient.class);

private Socket socket;

/**
* @param host
* @param port


*/
public TestSocketClient(String host, int port) {
super();
try {
socket = new Socket(host, port);
LOGGER.info(socket + " start to work.");
} catch (Exception e) {
LOGGER.error("Error:" + e.getMessage(), e);
}
}

public void talk() throws Exception {
BufferedReader localReader = new BufferedReader(new InputStreamReader(
System.in));
PrintWriter writer = new PrintWriter(socket.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
System.out.println(reader.readLine());
System.out.println("enter message :");
for (String request = localReader.readLine(); null != request; request = localReader
.readLine()) {
sendMsg(writer, request);
System.out.println(reader.readLine());
if (request.trim().equalsIgnoreCase("bye")) {
break;
}
}

IOUtils.closeQuietly(localReader);
socket.close();
}

private void sendMsg(PrintWriter writer, String msg) {
writer.println(msg);
writer.flush();
}

/**
* @param args
*/
public static void main(String[] args) {
try {
new TestSocketClient("localhost", 7777).talk();
} catch (Exception e) {
LOGGER.error("Error:" + e.getMessage(), e);
}

}

}


[解决办法]
client里面的代码,发现几个资源没有关闭。下面的代码进行了关闭。

大致思路就是分两个socket,多线程实现。
源码如下:
服务端代码:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class SocketTest {
public static void main(String[] args) {
time();
}

public static void time() {
long start = System.currentTimeMillis();
// 专门负责向socket中写数据
Socket writeSocket = null;
// 专门负责从socket中读数据
Socket readSocket = null;
try {
ServerSocket serverS = new ServerSocket(9000);
System.out.println("---等待客户端连接---");
// 服务端写操作对应客户端端读操作的socket
writeSocket = serverS.accept();
// 服务端读操作对应客户端读操作的socket
readSocket = serverS.accept();


System.out.println("---开始接收客户端消息---");

// 读客户端信息
FutureTask<Integer> readFuture = new FutureTask<Integer>(new ReadFromSocket(readSocket));
new Thread(readFuture).start();
// 写服务端信息
FutureTask<Integer> writeFuture = new FutureTask<Integer>(new WriteToSocket(
writeSocket, "Server"));
new Thread(writeFuture).start();

// 通过future的get操作,使线程处于持有状态,从而线程没有返回就不会结束
if (0 == readFuture.get() && 0 == writeFuture.get()) {
System.out.println("正常结束");
} else {
System.out.println("异常结束");
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
// 关闭各种资源的正确流程
try {
if (null != writeSocket) {
writeSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
System.out.println("总共连接时间:" + (end - start) + "(ms)");
}

}


客户端代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ClientTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
start();
long end = System.currentTimeMillis();
System.out.println("总共连接时间:" + (end - start) + "(ms)");
}

public static void start() {
// 专门负责从socket中读数据
Socket readSocket = new Socket();
// 专门负责向socket中写数据
Socket writeSocket = new Socket();
try {
// 客户端读操作对应服务端写操作的socket
readSocket.connect(new InetSocketAddress("127.0.0.1", 9000), 10000);// 连接不得超过10秒钟
// 客户端写操作对应服务端读操作的socket
writeSocket.connect(new InetSocketAddress("127.0.0.1", 9000), 10000);// 连接不得超过10秒钟
// 读服务端信息
FutureTask<Integer> readFuture = new FutureTask<Integer>(new ReadFromSocket(readSocket));
new Thread(readFuture).start();


// 写客户端信息
FutureTask<Integer> writeFuture = new FutureTask<Integer>(new WriteToSocket(
writeSocket, "Client"));
new Thread(writeFuture).start();

// 通过future的get操作,使线程处于持有状态,从而线程没有返回就不会结束
if (0 == readFuture.get() && 0 == writeFuture.get()) {
System.out.println("正常结束");
} else {
System.out.println("异常结束");
}
}// end try
catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
// 关闭各种资源的正确流程
try {
if (null != readSocket) {
readSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}


写socket线程类:
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Callable;

public class WriteToSocket implements Callable<Integer> {

// 可用的Socket链接
private Socket socket;

// 角色
private String role;

public WriteToSocket(Socket socket, String role) {
this.socket = socket;
this.role = role;
}

@Override
public Integer call() throws Exception {
// 合法性判断
if (null == socket
[解决办法]
!socket.isConnected()) {
System.out.println("非法的Socket链接!");
return -1;
}
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner sc = new Scanner(System.in);
String tmp = null;
for (; socket.isConnected() && !socket.isClosed();) {
tmp = sc.nextLine();
System.out.print("I say:" + tmp + System.getProperty("line.separator"));
bw.write(role + " say:" + tmp);
bw.newLine();
bw.flush();


if (tmp.endsWith("BYE")) {
break;
}
}
} catch (IOException e) {
System.out.println("Write---IO异常");
e.printStackTrace();
return -1;
} finally {
// 关闭各种资源的正确流程
if (null != socket) {
socket.close();
}
try {
if (null != bw) {
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

return 0;
}
}


读socket线程类:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.concurrent.Callable;

public class ReadFromSocket implements Callable<Integer> {

// 可用的Socket链接
private Socket socket;

public ReadFromSocket(Socket socket) {
this.socket = socket;
}

@Override
public Integer call() throws Exception {
// 合法性判断
if (null == socket
[解决办法]
!socket.isConnected()) {
System.out.println("非法的Socket链接!");
return -1;
}
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while (!socket.isClosed() && socket.isConnected() && null != (line = br.readLine())) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Read---IO异常");
e.printStackTrace();
return -1;
} finally {
// 关闭各种资源的正确流程
if (null != socket) {
socket.close();
}
try {
if (null != br) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();


}
}
return 0;
}

}

读书人网 >J2SE开发

热点推荐