您的位置:首页 > 编程语言

Socket编程

2015-08-06 21:36 363 查看
最近想写一个IM软件,因此研究了一下Socket编程,发现写Socket的时候有许多容易被忽略的细节需要注意,特做笔记记录。

一.Socket定义

二.Socket的阻塞式实现:

客户端主要代码:

<span style="font-family:Microsoft YaHei;font-size:18px;">private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case RECEIVE:
tv_msg.append("Server Msg:" + msg.getData().getString("msg") + "\n");
break;
}
}
};</span>


<span style="font-family:Microsoft YaHei;font-size:18px;">btn_msg.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
thread = new Thread(new MessageRunnable());
thread.start();
}
});</span>


<span style="font-family:Microsoft YaHei;font-size:18px;">private class MessageRunnable implements Runnable {

@Override
public void run() {
socket = new Socket();
Message message = new Message();
message.what = RECEIVE;
Bundle bundle = new Bundle();
try {
//连接服务器端的SOCKET
socket.connect(new InetSocketAddress(serverIP, serverPort), 5000);
//读出服务器端SOCKET的内容
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
OutputStream os = socket.getOutputStream();</span>
<span style="font-family:Microsoft YaHei;font-size:18px;">                //设置客户端的SOCKET读取inputstream的过时时间,如果服务端在这个时间内没有发送数据过来,则抛出SocketTimeoutException
socket.setSoTimeout(2000);
String line=null;
String msg = "";
Log.v("MainActivity","ready to read form server");
System.out.println("ready to read form server");
while ((line = bufferedReader.readLine()) != null) {
msg += line;
}
Log.v("MainActivity","read complete");
System.out.println("read complete");
//更新UI
bundle.putString("msg", msg);
message.setData(bundle);
myHandler.sendMessage(message);

//向服务器写内容
os.write(et_msg.getText().toString().getBytes("UTF-8"));
os.flush();

//关闭各种流和SOCKET
bufferedReader.close();
os.close();

} catch (SocketTimeoutException te) {
te.printStackTrace();
//连接请求超时
bundle.putString("msg", "time out");
message.setData(bundle);
myHandler.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();</span>
}
}
}


服务器端代码:

<span style="font-family:Microsoft YaHei;">public static void main(String args[]){

ServerSocket serverSocket=null;
try{
serverSocket=new ServerSocket(port);
}catch (IOException e){
e.printStackTrace();
}
System.out.println("server socket created");
while(true){
try{
Socket socket=serverSocket.accept();
System.out.println("socket accepted");
new Thread(new Runnable(){
@Override
public void run(){
BufferedReader reader=null;
OutputStream out=null;
try{
reader=new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
out=socket.getOutputStream();

System.out.println("server is ready to read");
String line="";
String next=null;
while((next=reader.readLine())!=null){
line+=next;
}
System.out.println("read complete");
System.out.println("client msg: "+line);

//Thread.sleep(5000);
System.out.println("ready to write to client");
out.write("i am socket server".getBytes("UTF-8"));
out.flush();
System.out.println("write complete");
//
//socket.shutdownOutput();

}catch(IOException e){
e.printStackTrace();
}
//catch (InterruptedException e) {
//	e.printStackTrace();
//}
finally{
try{
out.close();
}catch (IOException e){
e.printStackTrace();
}
try{
reader.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}).start();
}catch(IOException e){
e.printStackTrace();
}
}
}</span>


需要注意:

1.client端的connect方法和server端的accept方法是线程阻塞的,也就是说,在返回结果以前,线程是阻塞的。

2.有些资料说服务端和客户端不能同时创建输入流,实际上这个说法并不准确,经验证,同时创建输入流是完全可以的。事实上,server和client不能同时从输入流读取数据。为什么呢,因为inputstream的read方法是线程阻塞的,如果两边同时读取的话,两端都在等待对方输出数据,造成IO阻塞,因此需要一方先输出数据,另一方读取。

3.socket.shutdownOutput()方法,该方法的作用是关闭输出流。经验证,上述代码中如果少了这句,client端会继续读取inputstream中的内容,也就是阻塞。也就是说,只有关闭流后,才能终止read方法的阻塞状态。

4.socket.setSoTimeout()方法,设置socket读取输入流时的等待超时时间,必须在阻塞方法(read)之前调用。

三.Socket的非阻塞式实现:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: