如何 TCP 同步发送数据 ???(或者说是 阻塞block模式 ) 本帖最后由 CCDDzclxy 于 2013-11-01 11:02:04 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 在客户端这边不太好判断是否发送成功要知道是否发送完成,最好的办法是服务器端响应一个状态给你。PrintStream output = new PrintStream(skt.getOutputStream());output.write(bytes, 0, iLen);output.flush();//下面的代码如果继续执行表示数据已发送,至于服务器是否收到就很难说了。 这样还有TCP的优势么??这样弄还不如直接用UDP,自己弄个简单的重传机制了....... TCP数据传输理论上 数据比UDP可靠。客户端都是这样处理的,需要服务器响应状态。 所谓可靠不就是重传机制么。TCP里面本来就有接收方接收到数据会回传ACK,如果发送方一段时间没收到对方的ACK就会重传,这本就是TCP里面自带的。“最好的办法是服务器端响应一个状态给你”,这样不是浪费了ACK?不是浪费流量吗??? 你说的那个是TCP 底层的会保证数据完整性。正常情况下不会丢失数据。如果网络不稳定超时异常那就需要自己处理了。 比如我分别连续发了30次字符串“hello1”、“hello2”、“hello3”...“hello30”,但是对方网络断了。重传时间2分钟,然后抛出异常,那我如何知道 我是在 hello? 时 对方断网的?哪些字符串发送成功了,哪些没发送成功??? PrintStream output = new PrintStream(skt.getOutputStream());output.write("hello".getBytes(), 0, iLen); output.flush();//如果发送这个hello后,客户没有发生异常,可以理解为这个字符串已经发送成功了,不太可能只发送了前2个字符,后面几个字符没发送,如果真没发送那就是丢包了,这种情况是罕见的。try { PrintStream output = new PrintStream(skt.getOutputStream()); output.write(bytes, 0, iLen); output.flush();}catch(Exception ex){ //如果异常就需要处理那个字符串是没有发送成功。} 我的 客户端程序 基本设计成这样:接收数据的线程: Runnable threadRecv = new Runnable() { @Override public void run() { try { byte[] byteRecv = new byte[RECV_BUF_LENGTH]; InputStream input = Fskt.getInputStream(); while (true) { int iRecvLen = input.read(byteRecv, 0, RECV_BUF_LENGTH ); if ((iRecvLen == 0) || (-1 == iRecvLen)) { zcHandler.obtainMessage(THREAD_SKT_DEST_DISCONNECT).sendToTarget(); final String strBreak = "Socket closed by remote . Maybe connection timeout . ==> ("+Integer.toString(iRecvLen)+")"; zcHandler.obtainMessage(THREAD_MSG, strBreak).sendToTarget(); break; // 退出循环 } ...... ...... } // while } catch(Exception ex) { final String strErr = "Recv msg err : "+ex.getMessage()+"\r\n"; zcHandler.obtainMessage(THREAD_MSG, strErr).sendToTarget(); zcHandler.obtainMessage(THREAD_OVER).sendToTarget(); } } };发送数据的代码: Button btnTcpSend = (Button)findViewById(R.id.btnTcpSend); btnTcpSend.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { try { FiIdx ++; PrintStream output = new PrintStream(Fskt.getOutputStream()); output.write(FiIdx); output.flush(); } catch(Exception e) { String strErr = e.getMessage(); zcMsg_Add("Seng msg err : "+strErr); } } }); // btnTcpSendFiIdx 是初始化为 0 的类成员变量。测试步骤:CLient机子 和 Server机子 处于同一局域网,都是 XP 。Client机子 上运行 Android虚拟机来跑 客户端程序。1、Client 连上 Server 。2、连点 两次 btnTcpSend ,数字1、2 发出去了,server 也收到了。3、此时立即 禁用 Server 网卡,再立即点击 btnTcpSend 3次 。(此时时间为 12:52:15)4、抓包可见 ,数字3、4、5 在重传。5、时间 12:54:03 ,Android Client程序显示信息“Socket closed by remote . Maybe connection timeout . ==> (-1)” 。说明此时Client才知道对方断线了。(这个显示的信息是我在 接收线程里面的信息)这里,我是故意手动断开 server 的网络,所以我知道是 数字3、4、5 没发送成功。那么放到实际应用中,我怎么知道哪些发送成功了,哪些没发送成功 ??ps : 知道现在Client也没有别的信息显示 birdsaction 及 各位同仁,不管高手不高手,都来指点下啊~~~ 当你拔掉网线这个从socket角度来讲 很难判断,网都断了 Socket只是个接口无法知道物理层的详细东西。以前做应用一般都是捕获异常,或者服务器返回状态,如果没收到服务器的状态吗 就继续让程序发送请求。 android slidingdrawer 回弹效果 下载远程apk文件出错,求指教 android flash播放器 那位大哥在海信E90上开发过程序,请问你是如何与电脑连起来的? android中的power键按键检测 android自动加载第三方驱动 请问如何限制某些程序的安装? 用Calendar类做切换周的日历问题 使用AsyncTask遇到的一个奇怪现象 Activity如何取得创建好的Dialog的实例 关于andriod studio的问题 Listview异步加载图片,线程处理问题
要知道是否发送完成,最好的办法是服务器端响应一个状态给你。
PrintStream output = new PrintStream(skt.getOutputStream());
output.write(bytes, 0, iLen);
output.flush();
//下面的代码如果继续执行表示数据已发送,至于服务器是否收到就很难说了。
客户端都是这样处理的,需要服务器响应状态。
如果网络不稳定超时异常那就需要自己处理了。
output.write("hello".getBytes(), 0, iLen);
output.flush();
//如果发送这个hello后,客户没有发生异常,可以理解为这个字符串已经发送成功了,不太可能只发送了前2个字符,后面几个字符没发送,如果真没发送那就是丢包了,这种情况是罕见的。try {
PrintStream output = new PrintStream(skt.getOutputStream());
output.write(bytes, 0, iLen);
output.flush();
}catch(Exception ex){
//如果异常就需要处理那个字符串是没有发送成功。
}
接收数据的线程: Runnable threadRecv = new Runnable()
{
@Override
public void run()
{
try
{
byte[] byteRecv = new byte[RECV_BUF_LENGTH];
InputStream input = Fskt.getInputStream();
while (true)
{
int iRecvLen = input.read(byteRecv, 0, RECV_BUF_LENGTH ); if ((iRecvLen == 0) || (-1 == iRecvLen))
{
zcHandler.obtainMessage(THREAD_SKT_DEST_DISCONNECT).sendToTarget();
final String strBreak =
"Socket closed by remote . Maybe connection timeout . ==> ("+Integer.toString(iRecvLen)+")";
zcHandler.obtainMessage(THREAD_MSG, strBreak).sendToTarget();
break; // 退出循环
}
...... ......
} // while
}
catch(Exception ex)
{
final String strErr = "Recv msg err : "+ex.getMessage()+"\r\n";
zcHandler.obtainMessage(THREAD_MSG, strErr).sendToTarget();
zcHandler.obtainMessage(THREAD_OVER).sendToTarget();
}
}
};
发送数据的代码: Button btnTcpSend = (Button)findViewById(R.id.btnTcpSend);
btnTcpSend.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View v)
{
try
{
FiIdx ++;
PrintStream output = new PrintStream(Fskt.getOutputStream());
output.write(FiIdx);
output.flush();
}
catch(Exception e)
{
String strErr = e.getMessage();
zcMsg_Add("Seng msg err : "+strErr);
}
}
}); // btnTcpSend
FiIdx 是初始化为 0 的类成员变量。测试步骤:
CLient机子 和 Server机子 处于同一局域网,都是 XP 。Client机子 上运行 Android虚拟机来跑 客户端程序。
1、Client 连上 Server 。
2、连点 两次 btnTcpSend ,数字1、2 发出去了,server 也收到了。
3、此时立即 禁用 Server 网卡,再立即点击 btnTcpSend 3次 。(此时时间为 12:52:15)
4、抓包可见 ,数字3、4、5 在重传。
5、时间 12:54:03 ,Android Client程序显示信息“Socket closed by remote . Maybe connection timeout . ==> (-1)” 。说明此时Client才知道对方断线了。(这个显示的信息是我在 接收线程里面的信息)
这里,我是故意手动断开 server 的网络,所以我知道是 数字3、4、5 没发送成功。那么放到实际应用中,我怎么知道哪些发送成功了,哪些没发送成功 ??
ps : 知道现在Client也没有别的信息显示