在关闭另一端插槽后,Socket的输入流仍然获取数据

时间:2016-08-19 02:57:02

标签: java android sockets tcp network-programming

Socket的方法似乎不像其名称或文档所暗示的那样起作用。例如。我创建了一个客户端套接字来连接远程serversocket。当连接建立时,serversocket.accept()方法返回一个相应的套接字,该套接字来自客户端套接字的getinputstream。但问题是,如果我关闭客户端套接字,服务器上的套接字仍然会为isClosed()方法返回false;更荒谬的是,服务器上的Socket InputStream开始连续返回值,当客户端套接字关闭并且没有向服务器发送输出时不再阻塞。以下是我的代码:

客户代码:

public class MainActivity extends AppCompatActivity {
private Button startButton, stopButton;
public byte[] buffer;
public Socket socket;
public Socket tempSocket;
private int port = 50005;
InetSocketAddress address;
private int r_port = 50006;
AudioRecord recorder;
AudioTrack audioTrack;
private int sampleRate = 16000; // 44100 for music
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
public static boolean s_status = true;
public static boolean r_status = true;
Thread r_Thread;
Thread s_Thread;
private boolean isPlay = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    startButton = (Button) findViewById(R.id.start_button);
    startButton.setOnTouchListener(talkListener);
    if (socket == null) {
        socket = new Socket();
        address = new InetSocketAddress("192.168.0.2", port);
        try {
            socket.setReuseAddress(true);
            System.out.println("connecting-");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

private final View.OnTouchListener talkListener = new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                startButton.setBackgroundColor(Color.parseColor("#0670c0"));
                try {

                    startStreamings();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return true; // if you want to handle the touch event

            case MotionEvent.ACTION_UP:
                startButton.setBackgroundColor(Color.parseColor("#353535"));

                try {
                    s_status = false;

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

                    return true; // if you want to handle the touch event
                }
        }
        return false;
    }
};
public void startStreamings(){
    s_status=true;
    buffer = new byte[minBufSize];
    s_Thread = new Thread(new Runnable() {

        @Override
        public void run() {

            if (socket == null) {
                try {
                    socket = new Socket();
                    socket.setReuseAddress(true);

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (!socket.isConnected()) {
                try {
                    socket.connect(address);
                    System.out.println("create new connection in startStreaming");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, minBufSize * 10);
            try {
                if (s_status == true) {
                    recorder.startRecording();
                }
            } catch (IllegalStateException e) {
                e.printStackTrace();
                return;
            }

            OutputStream os = null;
            while (s_status == true) {

                //reading data from MIC into buffer
                recorder.read(buffer, 0, buffer.length);
                try {
                    os = socket.getOutputStream();
                    os.write(buffer, 0, minBufSize);
                } catch (Exception e) {
                    e.printStackTrace();
                    s_status = false;
                }
                //System.out.println("streaming out: " + buffer.length + "fff" + c++);
            }

            if (recorder != null) {
                recorder.stop();
                recorder.release();
                recorder = null;
            }
        }
    });
    s_Thread.start();
}

}

服务器代码:

    public TcpServerSocket(){

}

public static void main(String args[]) throws Exception {
 ServerSocket serverSocket = new ServerSocket(port);
 sockets = new ArrayList<Socket>();   
    while(isListenning){

        Socket socket = serverSocket.accept();
        isMatched = false;
        for(int i =0;i<sockets.size();i++){
            Socket preSocket = sockets.get(i);
            if(preSocket.getInetAddress().equals(socket.getInetAddress())){
                sockets.remove(preSocket);
                sockets.add(socket);
                isMatched = true;
            }
        }

        if(!isMatched){
            sockets.add(socket);
            socket.setKeepAlive(false);
            new Thread(new TcpServerSocket(socket)).start();
            System.out.println("new Connection");
        }


        }
    serverSocket.close();



 }

@Override
public void run() {


       byte[] receiveData = new byte[1280];
       byte[] emptyData = new byte[1280];
        InputStream baiss = null;

        OutputStream os;
        while (isRunning){
            try {
                baiss = csocket.getInputStream();

                if(csocket.isClosed()||!csocket.isConnected()){
                    isRunning = false;
                    sockets.remove(csocket);
                    System.out.println("socket closed!");
                }


                int numOfBytes = baiss.read(receiveData);
                if(numOfBytes==-1){
                    isRunning=false;
                    sockets.remove(csocket);
                    csocket.close();
                    System.out.println("socket closed!");
                }

            } catch (IOException e) {
                sockets.remove(csocket);
                System.out.println("socket closed!");
                e.printStackTrace();
            }
            int socketsLen = sockets.size();
            for(int i = 0;i<socketsLen;i++){
                Socket client = sockets.get(i);

                if(!client.getInetAddress().equals(csocket.getInetAddress())){
                    try {
                    os = client.getOutputStream();
                    os.write(receiveData,0,1280);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }else if(!client.equals(csocket)){
                    csocket = client;
                    System.out.println("switched!");
                }
            }

        System.out.println(csocket.getInetAddress().toString()+"fff"+socketsLen);
        }
        try {
            baiss.close();
            csocket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


}

你能否给我任何关于完全关闭客户端套接字的建议,以便在关闭客户端后我不会继续输入?非常感谢任何帮助!

1 个答案:

答案 0 :(得分:2)

  关闭另一端套接字后

socket.getInputStream()仍然获取数据

这可能是因为仍有传输中的数据尚未被读取。关闭连接不会中止待处理的数据传输。但事实证明,它根本没有获得数据。您的代码中只有一个错误。

  

最近几天我对socket非常不满。

我建议你克服自己心烦意乱并对所选职业采取理性态度。

  

我发现套接字的方法不能按照其名称或文档的方式起作用。

让我们看看。

  

例如。我创建了一个客户端套接字来连接远程serversocket。当连接建立时,serversocket.accept()方法返回一个相应的套接字,该套接字来自客户端套接字的getinputstream。但问题是,如果我关闭客户端套接字,服务器上的套接字仍然为isClosed()方法返回true

不,它没有。它返回false。服务器的套接字仍处于打开状态。 客户端套接字已关闭,连接也是如此,但isClosed()会告诉您调用套接字的状态,而不是其他任何内容,特别是不是连接。

  

更荒谬的是,服务器上的socket.getInputStream()开始连续返回值,当客户端套接字关闭并且没有向服务器发送输出流时,不再阻塞。

仅在对等方关闭之前有飞行数据。否则,这是由于您的代码中存在错误,现在是:

//reading data from MIC into buffer
recorder.read(buffer, 0, buffer.length);

read()在流结束时返回-1,而您忽略它。 那是为什么你会得到一个连续的循环。编写此代码的正确方法如下:

int count = recorder.read(buffer, 0, buffer.length);
if (count == -1) {
    recorder.close();
    socket.close();
    break;
}
try {
    os = socket.getOutputStream();
    os.write(buffer, 0, count);

您的客户端代码存在类似问题。你似乎并不关心流的结束:

baiss = csocket.getInputStream();
if(csocket.isClosed()||!csocket.isConnected()){
    isRunning = false;
    sockets.remove(csocket);
    System.out.println("socket closed!");
}
baiss.read(receiveData);
// ...
os = client.getOutputStream();
os.write(receiveData,0,1280);

写这个的正确方法如下:

baiss = csocket.getInputStream();
int count = baiss.read(receiveData);
if(count == -1){
    isRunning = false;
    sockets.remove(csocket);
    System.out.println("socket closed!");
}
// ...
os = client.getOutputStream();
os.write(receiveData, 0, count);
  

你能否给我任何关于完全关闭客户端插座的建议,以便在我关闭客户端后不会继续获取输入?

你正在完美地关闭它。问题是你没有在另一端正确检测到它。