there's simple socket program (server / client) i made.
server is working on windows and client is android app which contains shared library made of c socket.
in client side, to avoid freeze i changed socket to NON_BLOCK than rollback to BLOCK socket after passing connect() function. after that, i search connection is available using getpeername().
as below...
flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags|O_NONBLOCK);
nRet = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
if (nRet < 0)
if (errno != EINPROGRESS && errno != EWOULDBLOCK)
return ERR_CONN;
...
...
nRet = select(sock+1, &readset, &writeset, NULL, &tv);
if (nRet == 0)
if (errno != EINPROGRESS && errno != EWOULDBLOCK)
return ERR_SELECT;
nRet = getpeername(sock, (struct sockaddr*)&addr, &len);
if (nRet != 0)
return ERR_GETPEER;
fcntl(sock, F_SETFL, flags);
everything's working well. except working on 3G mode.
sometimes even if Server got connection, client side return errors in getpeername().
error code is ENOTCONN.
what should i implement to avoid this? any suggestion would be appreciate.
thx in advance.
i found what's wrong.
first, i should roll back to BLOCK socket after passing connect() not before return.
second, it seems that select() doesn't guarantee to hold for timeval, so i made function like GetTickCount() than counted time to break loop.
here's my solution.
fcntl(O_NONBLOCK);
connect();
fcntl(BLOCK);
while (true)
{
fd_set rdfs, wdfs;
FD_ZERO(&rdfs); FD_ZERO(&wdfs);
FD_SET(sock, &rdfs); FD_SET(sock, &wdfs);
tv.tv_sec = 0; tv.tv_usec = 100;
nRet = select(sock + 1, &rdfs, &wdfs, NULL, &tv);
if (nRet == -1) return -1;
else if (nRet)
{
nRet = getpeername();
if (!nRet)
break;
}
if (get_tick_count() - delay > timeout)
return -2;
}
thx! sarnold, caf :)
To determine if the socket is connected, it is more usual to use getsockopt() rather than getpeername():
int so_error;
socklen_t len = sizeof so_error;
getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0) {
/* socket is connected */
}
Related
I am using esp32 to bring up a tcp server. In order not to access this server by ip, I use mDNS on the esp32 side. I can successfully contact the tcp server from the PC at esp32.local. Now I want to do the same from android application. I wrote a little c ++ code which I run on android.
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
hello ="socket creation failed...";
return env->NewStringUTF(hello.c_str());
}
else
hello="Socket successfully created..\n";
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
std::string url = "esp32.local";
servaddr.sin_addr.s_addr = inet_addr(url.c_str());
servaddr.sin_port = htons(1234);
struct hostent *result;
result = gethostbyname(url.c_str());
// destAddr.sin_addr.s_addr = ((in_addr*)hosten->h_addr_list[0])->s_addr;
if (!result)
{
hello ="gethostbyname...";
return env->NewStringUTF(hello.c_str());
}
// puts(result->h_name);
memmove(&(servaddr.sin_addr.s_addr), result->h_addr, result->h_length);
// connect the client socket to server socket
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) {
hello="connection with the server failed..";
return env->NewStringUTF(hello.c_str());
}
else
printf("connected to the server..\n");
// function for chat
char buff = 0xA;
write(sockfd, &buff, sizeof(buff));
// close the socket
close(sockfd);
When trying to connect from android application, I get an error in function gethostbyname. . What do I need to do to access the .local domain?
std::string url = "esp32.local";
servaddr.sin_addr.s_addr = inet_addr(url.c_str());
inet_addr() does not support parsing hostnames like "sp32.local", only IP addresses. You need to use gethostbyname() or better getaddrinfo() instead.
struct hostent *result;
result = gethostbyname(url.c_str());
...
memmove(&(servaddr.sin_addr.s_addr), result->h_addr, result->h_length);
You are not copying the result of gethostbyname() into the sin_addr.s_addr correctly. Your commented-out code was doing it correctly:
servaddr.sin_addr.s_addr = ((in_addr*)(hosten->h_addr_list[0]))->s_addr;
Which can be simplified to:
servaddr.sin_addr = *(in_addr*)(hosten->h_addr_list[0]);
Or just:
servaddr.sin_addr = *(in_addr*)(hosten->h_addr);
But, getaddrinfo() would be easier to use than populating a sockaddr_in manually. And it supports IPv6, whereas gethostbyname() only supports IPv4:
std::string url = "esp32.local";
int sockfd = -1;
addrinfo hints = {};
addrinfo *result;
hints.ai_family = AF_INET; // AF_UNSPEC
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// assign IP, PORT
int res = getaddrinfo(url.c_str(), "1234", &hints, &result);
if (res != 0) {
return env->NewStringUTF("getaddrinfo failed...");
}
for(addrinfo *addr = result; addr; addr = addr->ai_next) {
// socket create and varification
sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sockfd == -1) {
continue;
}
// connect the client socket to server socket
if (connect(sockfd, addr->ai_addr, addr->ai_addrlen) != 0) {
close(sockfd);
sockfd = -1;
continue;
}
break;
}
if (sockfd == -1) {
freeaddrinfo(result);
return env->NewStringUTF("socket creation/connect failed...");
}
freeaddrinfo(result);
printf("Connected to the server..\n");
// function for chat
char buff = 0xA;
write(sockfd, &buff, sizeof(buff));
// close the socket
close(sockfd);
I am using a TCP socket connection in an action game, we use lockstep synchronization, client will receive 20 - 40 packets per second. It works fine when the game is running on a PC but when running on Android devices, the socket will get stuck every 20 seconds
Server sends 5 packets per second
I have tried to use Unity3D's C# socket, Android Java socket and Android native C socket and blocking/non-blocking mode, small/large (1byte/100byte) data per packet, less/more (5/50) packets per second, use single thread/main thread, on multiple Android devices, all of them have the same issue.
PS: It seems the 20 second duration is based on devices, not my app or connection; that means if last stuck happens at 1:00:00, the next stuck will happen at 1:00:20, even if we reconnect or restart the app.
Android native C code:
extern "C" JNIEXPORT int JNICALL
Java_com_example_ymoon_sockettest_MainActivity_connect(JNIEnv *env, jobject /* this */)
{
__android_log_print(ANDROID_LOG_INFO, "CSocket", "Connecting...");
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) return -1;
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(12350);
server.sin_addr.s_addr = inet_addr("192.168.3.66");
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0)
{
close(sock);
return -2;
}
__android_log_print(ANDROID_LOG_INFO, "CSocket", "Connected");
char buf[100];
int t = -1;
int received = 0;
while (true)
{
int count = recv(sock, &buf, 100, 0);
if (count < 1) break;
received += count;
struct timeval tv;
gettimeofday(&tv, NULL);
int m = tv.tv_sec * 1000 + tv.tv_usec / 1000;
int diff = m - t;
t = m;
std::string p = t < 0 ? "" : diff < 50 ? "-" : diff < 100 ? "-|" : diff < 150 ? "--|" :
diff < 250 ? "---|" : diff < 500 ? "----|" : diff < 1000 ? "-----|" : "------|";
__android_log_print(diff > 500 ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO,
"CSocket", "%i | %s %i", received, p.c_str(), diff);
}
close(sock);
return 0;
}
Am I doing something wrong ?
It is my first time to ask a question on stackoverflow, sorry for my bad English, any help or suggestion is appreciated, thanks.
Edit: add server code, i rewrite a simple tcp server to test (Window platform)
int main()
{
addrinfo conf, *add = nullptr;
memset(&conf, 0, sizeof(conf));
conf.ai_flags = AI_PASSIVE;
conf.ai_socktype = SOCK_STREAM;
conf.ai_family = AF_INET;
if (getaddrinfo(nullptr, "12350", &conf, &add)) return 0;
SOCKET serverSock = socket(AF_INET, SOCK_STREAM, 0);
char opt = 1;
if (setsockopt(serverSock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
setsockopt(serverSock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) == -1 ||
bind(serverSock, add->ai_addr, add->ai_addrlen) == -1 ||
listen(serverSock, 0) == -1)
{
close(serverSock);
return 0;
}
printf("Listening....\n");
sockaddr_storage incoming_addr;
int size = sizeof(incoming_addr);
SOCKET clientSock = accept(serverSock, (sockaddr*)&incoming_addr, &size);
printf("Client connected\n");
char buf[1] = { 0 };
int sendCount = 0;
while (true)
{
time_t t = time(nullptr);
tm *lt = localtime(&t);
printf("%02d:%02d:%02d Send to client %i\n", lt->tm_hour, lt->tm_min, lt->tm_sec, ++sendCount);
if (send(clientSock, buf, 1, 0) < 1) break;
Sleep(200);
}
close(serverSock);
return 0;
}
Edit: Add WireShark capture image:
Wireshark shot when stuck happen
I have test it (code posted here) in my home, and another WIFI environment, it worked fine. The only difference is the WIFI environment, so I think maybe our company WIFI network settings cause this issue.
I have written a socket program in c. This program will send data from my android phone to my PC. Here what i need that i want to increase my data buffer size to a larger one so that i could send a large data. I used setsockopt() system call to increase the tcp buffer size. But my android not allowing me to increase the size beyond 4096 bytes. Following i pasted my Server side code. Need help
int listenfd = 0;
//Create a socket
if((listenfd = socket(AF_INET, SOCK_STREAM, 0))==-1)
{
printf("\n Could not create socket..");
return -1;
}
sock_buf_size=8192;
setsockopt( listenfd, SOL_SOCKET, SO_SNDBUF,(char *)&sock_buf_size , sizeof(sock_buf_size));
setsockopt( listenfd, SOL_SOCKET, SO_RCVBUF,(char *)&sock_buf_size , sizeof(sock_buf_size));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(8888);
// sock_buf_size = SOCKET_BUFF_SZ;
//Binding the socket
if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1 )
printf("\nBind failed ");
else puts("\nBind done");
//Listen to incoming connections
listen(listenfd, 5);
//Accept an incoming connection
puts("\nWaiting for incoming connections...");
c = sizeof(struct sockaddr_in);
connfd = accept(listenfd, (struct sockaddr*)&client, &c);
if((RcvdByteCnt = recv(connfd ,pSendBuff , BuffLength, 0)) != -1)
{
printf("\n Revived Byte->%d",RcvdByteCnt );
}
I have set a UDP non-blocking socket. I am creating the socket, binding it, and joining a multicast group like this:
int hopLimit = 1;
int bAllowMultiple = 1;
in_addr localAddr;
localAddr.s_addr = 0;
in_addr groupAddress;
groupAddress.s_addr = inet_addr(ADDRESS);
sockaddr_in groupEndPoint;
groupEndPoint.sin_family = AF_INET;
groupEndPoint.sin_addr = groupAddress;
groupEndPoint.sin_port = htons(PORT);
SOCKET udpsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(udpsocket == -1){
printf("Socket fail\n%d\n", errno);
return 1;
}
if(setsockopt(udpsocket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&hopLimit, sizeof(hopLimit))==-1){
printf("sockopt failed: IP_MULTICAST_TTL\n%d\n", errno);
return 1;
}
if(setsockopt(udpsocket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localAddr, sizeof(localAddr))==-1){
printf("sockopt failed: IP_MULTICAST_IF\n%d\n", errno);
return 1;
}
if(setsockopt(udpsocket, SOL_SOCKET, SO_REUSEADDR, &bAllowMultiple, sizeof(bAllowMultiple))==-1){
printf("sockopt failed: SO_REUSEADDR\n%d\n", errno);
return errno;
}
// Set to non-blocking mode
unsigned long bMode = 1;
if(ioctl( udpsocket, FIONBIO, &bMode )==-1){
printf("ioctl failed\n%d\n", errno);
return errno;
}
sockaddr_in localEndPoint;
localEndPoint.sin_family = AF_INET;
localEndPoint.sin_addr.s_addr = localAddr.s_addr;
localEndPoint.sin_port = groupEndPoint.sin_port;
// Bind the socket to the port
int r = bind(udpsocket, (sockaddr*)&localEndPoint, sizeof(localEndPoint));
if (r != 0)
{
printf("Bind failed\n%d\n", errno);
return errno;
}
// Join the multicast group
struct ip_mreq imr;
imr.imr_multiaddr = groupEndPoint.sin_addr;
imr.imr_interface.s_addr = groupEndPoint.sin_addr.s_addr;
r = setsockopt(udpsocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
printf("%d\n",r);
if (r == -1){
printf("sockopt failed: IP_ADD_MEMBERSHIP\n%d\n", errno);
return errno;
}
The first 3 setsockopt calls - MULTICAST_TTL, MULTICAST-IF and REUSEADDRESS - work fine, and it binds. When I then try to join the multicast group it returns errno 19 - Device Not Found. Changing the imr interface address to INADDR_ANY means the device is found, but the program won't receive packets. I've changed the ADDRESS, I know it is in the multicast range. eth0 on my machine has multicast enabled. I've tried using struct ip_mreqn imr and changed interface to address appropriately, no change. I ran a stack trace, but it's no more informative, just says setsockopt failed with errno 19.
Does anyone have any ideas? I'm a bit desperate here, I've been on this for way too long.
I'm trying to produce a simple server that will allow me test the Androids security features. I need to develop an application that will open a socket.
I've produced something similar in C, but I am having no look with java. Here's the application in C
// simpleserver3.c
#define MY_PORT 9999
#define MAXBUF 99
void indata(int clientfd, struct sockaddr_in client_addr)
{
char buffer[12];
printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
recv(clientfd, buffer, MAXBUF, 0); //this is will overflow the buffer
printf("%X \n", &buffer);
}
int main(int Count, char *Strings[])
{
struct sockaddr_in self, client_addr;
int sockfd,clientfd;
/*---Create streaming socket---*/
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) //socketfd = handle for socket
{
perror("Socket");
exit(errno);
}
/*---Initialize address/port structure---*/
bzero(&self, sizeof(self));
self.sin_family = AF_INET;
self.sin_port = htons(MY_PORT);
self.sin_addr.s_addr = INADDR_ANY;
/*---Bind the structure to the socket handle ---*/
if ( bind(sockfd, (struct sockaddr*)&self, sizeof(self)) != 0 )
{
perror("socket--bind");
exit(errno);
}
/*---Make it a "listening socket"---*/
if ( listen(sockfd, 20) != 0 )
{
perror("socket--listen");
exit(errno);
}
//set socklen_t to length of client address
socklen_t addrlen=sizeof(client_addr);
/*---accept a connection (creating a data pipe)---*/
clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen); //create handle for communicating
indata(clientfd, client_addr);
close(clientfd);
close(sockfd);
return;
}
Any sugguestion would be great, Aneel
It's been a while since I used C, so I can't comment on your C code, but you should probably take a look at the Android documentation for the Socket class:
http://developer.android.com/reference/java/net/Socket.html
Check out this example: http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/