【发布时间】:2016-08-23 17:00:28
【问题描述】:
我正在尝试在我的桌面上创建一个套接字服务器并从我的 android 连接到它,但是,除非服务器在发送数据后关闭连接,否则 android 无法从套接字读取。
桌面服务器代码:
#define SERVER_BUFLEN 512
#define SERVER_PORT "27033"
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
int main () {
setvbuf(stdout, NULL, _IONBF, 0);
WSADATA wsaData;
int iResult;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char recvbuf[SERVER_BUFLEN];
int recvbuflen = SERVER_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, SERVER_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
ListenSocket = INVALID_SOCKET;
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
ListenSocket = INVALID_SOCKET;
WSACleanup();
return 1;
}
printf ("waiting for new client\n");
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
}
printf ("new client connected\n");
//int flag = 1;
//setsockopt(ClientSocket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
do {
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
iSendResult = send( ClientSocket, recvbuf, iResult, 0 );
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
}
printf("Bytes sent: %d\n", iSendResult);
//iResult = shutdown(ClientSocket, SD_SEND);
} else if (iResult == 0) {
printf("Connection closing...\n");
} else {
printf("recv failed with error: %d\n", WSAGetLastError());
}
} while (iResult > 0);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
}
closesocket(ClientSocket);
printf ("client left\n");
if (ListenSocket != INVALID_SOCKET) {
closesocket(ListenSocket);
}
WSACleanup();
return 0;
}
Android 客户端代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate");
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
try {
Socket sock = new Socket();
//sock.setReceiveBufferSize(10);
sock.connect(new InetSocketAddress("192.168.0.101", 27033));
OutputStream os = sock.getOutputStream();
InputStream is = sock.getInputStream();
String msg = "Hello World!\r\n\0";
byte[] arr = msg.getBytes(Charset.forName("UTF-8"));
os.write(arr);
os.flush();
Log.d(TAG, "RECV MSG: " + is.read ());
sock.close();
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
服务器的输出是:
waiting for new client
new client connected
Bytes received: 15
Bytes sent: 15
recv failed with error: 10060
client left
客户端的输出是:
08-23 18:29:55.997 26472-26472/com.example.greg.systemremote D/MainActivity: onCreate
08-23 18:29:55.997 26472-26472/com.example.greg.systemremote D/libc-netbsd: [getaddrinfo]: hostname=192.168.0.101; servname=(null); netid=0; mark=0
08-23 18:29:55.997 26472-26472/com.example.greg.systemremote D/libc-netbsd: [getaddrinfo]: ai_addrlen=0; ai_canonname=(null); ai_flags=4; ai_family=0
08-23 18:33:54.254 26472-26472/com.example.greg.systemremote D/MainActivity: recvfrom failed: ETIMEDOUT (Connection timed out)
请注意,客户端没有收到任何消息。
我尝试使用
禁用 Nagleint flag = 1;
setsockopt(ClientSocket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
但它并没有改变任何东西,所以我尝试使用 Wireshark 检查网络流量,从输出中可以看到,数据正在发送到 android: (192.168.0.183 是安卓设备)
但是,如果我取消注释该行
iResult = shutdown(ClientSocket, SD_SEND);
从而在发送数据后关闭连接,在android端接收到,网络流量如下:
android 输出是
08-23 18:47:41.984 13164-13164/com.example.greg.systemremote D/MainActivity: onCreate
08-23 18:47:41.985 13164-13164/com.example.greg.systemremote D/libc-netbsd: [getaddrinfo]: hostname=192.168.0.101; servname=(null); netid=0; mark=0
08-23 18:47:41.985 13164-13164/com.example.greg.systemremote D/libc-netbsd: [getaddrinfo]: ai_addrlen=0; ai_canonname=(null); ai_flags=4; ai_family=0
08-23 18:47:42.318 13164-13164/com.example.greg.systemremote D/MainActivity: RECV MSG: 72
(名义上的)
所以,我的问题是,如何在不关闭连接的情况下在此套接字连接上发回和第四次发送数据?另请注意,我打算发送二进制数据,而不是文本。
【问题讨论】:
标签: java android c++ sockets network-programming