您可以同时写入套接字输入和输出流吗?
Posted
技术标签:
【中文标题】您可以同时写入套接字输入和输出流吗?【英文标题】:Can you write to a sockets input and output stream at the same time? 【发布时间】:2013-01-07 19:06:43 【问题描述】:我有一个 Java 应用程序,它是 Voip。我正在使用一个套接字通过线程同时发送和接收信息。代码如下所示..
Socket clientSocket = sockList.accept();
OutputStream outSock = clientSocket.getOutputStream();
InputStream inSock = clientSocket.getInputStream();
new Thread( new Capture(outSock)).start();
new Thread( new PlayAudio(inSock)).start();
outSock.close();
clientSocket.close();
我发现的问题是,当我写入输出流时,它会在第一次写入时阻塞。我发送的字节不多。下面是我写的代码。
private class Capture implements Runnable
private OutputStream out;
public Capture(OutputStream out)
this.out = out;
@Override
public void run()
try
int numBytesRead;
TargetDataLine outLine = getMic();
outLine.open();
outLine.start();
byte[] data = new byte[outLine.getBufferSize() / 5];
byte[] test = 0x1,0x1,0x1;
while(true)
//numBytesRead = outLine.read(data, 0, data.length);
//System.out.println(numBytesRead);
out.write(test, 0, test.length);
out.flush();
/*if(numBytesRead > 0)
out.write(data, 0, data.length);
System.out.println("C");
*/
catch(Exception ex)
另一个读取声音代码的线程是……
private class PlayAudio implements Runnable
private InputStream in;
public PlayAudio(InputStream in)
this.in = in;
@Override
public void run()
int write;
try
SourceDataLine inLine = getSpeaker();
inLine.open();
inLine.start();
byte[] data = new byte[inLine.getBufferSize()];
byte[] test = new byte[3];
while(true)
System.out.println(1);
//write = in.read(data, 0, data.length);
in.read(test, 0 , test.length);
System.out.println(2);
/*if(write > 0)
inLine.write(data, 0, write);
System.out.println(3);
System.out.println(write);
*/
catch(Exception ex)
我已经注释了大部分实际代码,因为我只是想让它工作。我的写入功能在第一次写入时无限期阻塞。这可能是我的线程的问题吗?我唯一的想法是输出和输入流共享我的套接字对象,这可能会导致死锁或其他东西。请让我知道发生了什么。
【问题讨论】:
【参考方案1】:是的,您可以同时写入套接字输入和输出流。
来自do-java-sockets-support-full-duplex
由于输入流和输出流是 Socket 中的独立对象,您唯一可能关心的是,如果您有 2 个线程尝试读取或写入会发生什么(两个线程,相同的输入/输出流)同时? InputStream/OutputStream 类的读/写方法不同步。但是,如果您使用 InputStream/OutputStream 的子类,则您调用的读/写方法可能是同步的。您可以检查 javadoc 以了解您正在调用的任何类/方法,并很快找到。
【讨论】:
我认为既然输入和输出(两个独立的流)是独立的对象,同时对它们进行操作应该没关系。所以你说我还是应该担心同步?【参考方案2】:是的,您可以在读取时在套接字上写入,但您必须在独立线程中读取套接字。我正在使用这个概念。这里的例子是(仔细阅读它也支持多个客户端):
public class TeacherServerSocket
private Logger logger = Logger.getLogger(TeacherServerSocket.class);
public static Map<String, TeacherServerThread> connectedTeacher = new HashMap<String, TeacherServerThread>();
ServerSocket serverSocket;;
@Override
public void run()
// starting teacher server socket
this.serverSocket = startServer();
// if unable to to start then serverSocket would have null value
if (null != this.serverSocket)
while (true)
//listening to client for infinite time
Socket socket = listenToClient();
if (null != socket)
TeacherServerThread teacherServerThread = new TeacherServerThread(socket);
Thread thread = new Thread(teacherServerThread);
thread.start();
//putting teacher ip address and teacher object into map
connectedTeacher.put(teacherServerThread.getTeacherIp(),teacherServerThread);
System.out.println("INFO: Teacher is connected with address "+ teacherServerThread.getTeacherIp());
@Override
public ServerSocket startServer()
//port number on which teacher server will be run.
int port=12345;
try
// throw an exception if unable to bind at given port
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Teacher server socket started on port no :"+port);
return serverSocket;
catch (IOException e)
logger.error("Unable to start Teacher Server socket");
e.printStackTrace();
return null;
@Override
public Socket listenToClient()
if (this.serverSocket != null)
try
// throw an exception is unable to open socket
Socket socket = this.serverSocket.accept();
return socket;
catch (IOException e)
logger.error("Unable to open socket for teacher");
e.printStackTrace();
else
logger.error("TeacherServerSocket has got null value please restart the server");
return null;
@Override
public Map getConnectedDevicesMap()
return TeacherServerSocket.connectedTeacher;
/**
* This method will send message to connected teacher which comes form student
* @author rajeev
* @param message, which comes form student
* @return void
* * */
@Override
public void publishMessageToClient(String message)
if(TeacherServerSocket.connectedTeacher.size()>0)
System.out.println("Total Connected Teacher: "+TeacherServerSocket.connectedTeacher.size());
for (String teacherIp : TeacherServerSocket.connectedTeacher.keySet())
TeacherServerThread teacherServerThread=TeacherServerSocket.connectedTeacher.get(teacherIp);
teacherServerThread.publishMessageToTeacher(message);
@Override
public void stopServer()
if (this.serverSocket != null)
try
serverSocket.close();
catch (Exception e)
e.printStackTrace();
在一个独立的线程中读取多个客户端:
public class TeacherServerThread implements Runnable
Logger logger=Logger.getLogger(TeacherServerThread.class);
Socket socket;
String teacherIp;
public TeacherServerThread(Socket socket)
this.socket=socket;
this.teacherIp=socket.getInetAddress().toString();
@Override
public void run()
//starting reading
ReadFromTeacherAndPublishToStudent messageReader=new ReadFromTeacherAndPublishToStudent();
Thread thread=new Thread(messageReader);
thread.start();
private class ReadFromTeacherAndPublishToStudent implements Runnable
@Override
public void run()
String message=null;
try
BufferedReader readTeacherData=new BufferedReader(new InputStreamReader(socket.getInputStream()));
StudentServerSocket studentServerSocket=new StudentServerSocket();
//sending message to student which is read by teacher
while((message=readTeacherData.readLine())!=null)
//System.out.println("Message found : "+message);
// studentServerSocket.publishMessageToClient(message); // do more stuff here
// if message has null value then it mean socket is disconnected.
System.out.println("INFO: Teacher with IP address : "+teacherIp+" is disconnected");
TeacherServerScoket.connectedTeacher.remove(getTeacherIp());
if(null!=socket)
socket.close();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
//class
public void publishMessageToTeacher(String message)
if(this.socket!=null)
try
PrintWriter writeMessageToTeacher=new PrintWriter(this.socket.getOutputStream());
writeMessageToTeacher.println(message);
writeMessageToTeacher.flush();
System.out.println(" Message published to teacher"+message);
catch(Exception e)
logger.error(e.toString());
logger.error("Exception In writing data to teacher");
else
logger.error("Unable to publish message to teacher .Socket has Null value in publishMessageToTeacher");
System.out.println("ERROR: socket has null value can not publish to teacher");
public String getTeacherIp()
return teacherIp;
根据您的要求更改代码......
【讨论】:
我正在使用线程进行读写。一个线程读取,另一个线程写入。我也不能使用 PrintWriter 因为我必须发送原始字节数组,这就是我的音频数据所在。【参考方案3】:我的 write() 似乎阻塞的原因是我愚蠢地关闭了 Socket() 而我的输入流没有意识到这一点。因此,永远不会发送任何数据。代表我犯了愚蠢的错误。
【讨论】:
以上是关于您可以同时写入套接字输入和输出流吗?的主要内容,如果未能解决你的问题,请参考以下文章