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/
Related
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've implemented a C native function with for android NDK, to send UDP packets.
I have a working receiver but i seem to get nothing when i use the sender.
How can i get more info from the return value of sendto? I'm having a hard time debugging native functions - no "debug step mode"
can anyone see anything wrong about the sender code? is there something im not doing right?
Thanks!
jstring
Java_com_example_adhocktest_SenderUDP_SendUdpJNI( JNIEnv* env,
jobject thiz, jstring ip, jstring message)
{
int PORT = 8888;
int i;
int sock_fd;
char *_ip = (*env)->GetStringUTFChars(env, ip, 0);
char *send_buf = (*env)->GetStringUTFChars(env, message, 0);
////////////////
//////// create socket
////////////////
if (( sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
return (*env)->NewStringUTF(env,"Cannot create socket");
}
struct sockaddr_in myaddr;
////////////////
//////// send
////////////////
struct sockaddr_in servaddr;
memset((char*)&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = 8888;
if ((inet_aton(_ip,&servaddr.sin_addr)) == 0) {
return (*env)->NewStringUTF(env,"Cannot decode IP address");
}
int retval = sendto(sock_fd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
close(sock_fd);
char str[100];
if ( retval < 0) {
sprintf(str, "sendto failed with %d", retval);
} else {
sprintf(str, "sendto success with %d", retval);
}
return (*env)->NewStringUTF(env,str);
}
The problem in the code was this line
servaddr.sin_port = 8888;
the correct line would be
servaddr.sin_port = htons(8888);
the reason for this was explained here by
bornruffians:
" htons() stands for "host-to-network short". On a given platform
(called the host), it converts the endianness of a short (16-bit
generally) integer to the endianness required for sending on the
network (generally big endian).
sendto() returns the number of bytes sent. You should check that
retval is the string length of your 'send_buf' variable, not just a
positive value."
Thanks all for your help,
Ben.
If it's still not working, did you give your app the necessary permissions for manipulating sockets?
<uses-permission android:name="android.permission.INTERNET" />
htons() stands for "host-to-network short". On a given platform (called the host), it converts the endianness of a short (16-bit generally) integer to the endianness required for sending on the network (generally big endian).
sendto() returns the number of bytes sent. You should check that retval is the string length of your 'send_buf' variable, not just a positive value.
I wanted to create a socket and bind it to an interfaces ip address so that packet goes through that interface only on android in native layer. But on bind() system call I get an error Address family not supported. However I think I have given address family as AF_INET.
local = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
memset(local,'\0',sizeof(sockaddr_in));
local->sin_family = AF_INET;
optval2 = "wlan0";
memset(&ifr, 0, sizeof(struct ifreq));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), optval2);
if(ioctl(sock, SIOCGIFADDR, &ifr) == 0) {
__android_log_print(3, DEBUG_TAG, "ioctl success");
}
ip = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
local->sin_addr.s_addr = inet_addr(ip);
local->sin_port = 0;
if(bind(sock, (struct sockaddr*)&local, sizeof(struct sockaddr_in)) < 0 ) {
__android_log_print(3, DEBUG_TAG, "error %d string %s", errno, strerror(errno));
}
Any help would be greatly appreciated.
Shouldn't this part of the bind call:
(struct sockaddr*)&local
be
(struct sockaddr*)local
since local already is a pointer?
How can I turn on or turn off a switch using Android and a Wi-Fi connection?
I have used SparkFuns IOIO to control relays. But how do I do it wirelessly?
I have a project just like this. Mine is sending position data for a steering system, but the idea is the same. I'll finish uploading it to Google Code soon. You can check it out at PowerWheelino.
The basic structure is this:
Touch event on Android sends data (over UDP) to the server.
The UDP server (WRT54G router in this case) receives the data and forwards it over serial to the Arduino.
The Arduino decides what to do with the data from the serial connection.
Keep in mind that the Arduino automatically resets when receiving data over serial (outside of the IDE Serial interface). See my post here on this topic and ways to get around it. Knowing this previously would have saved me a lot of troubleshooting.
Disclaimer:
This code requires some minor modification to accomplish what was requested by the OP. Since you've already made a working Android program with IOIO and an Arduino sketch, I assume this is within your abilities.
Here's the Android UDP client code:
Execute UdpClient::sendData() on touch event or button press.
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import android.util.Log;
public class UdpClient {
String messageStr;
DatagramSocket s;;
int server_port;
InetAddress local;
int msg_length;
byte[] message;
public UdpClient (String ipAddress, int port){
server_port = port;
try {
local = InetAddress.getByName(ipAddress);
s = new DatagramSocket();
}
catch (Exception e) {
e.printStackTrace();
Log.d("Powerwheelino",e.getStackTrace() + "error");
}
}
public boolean sendData(byte drive, byte steering){
byte drvByte = (byte) (drive & 0xFF);
byte steerByte = (byte) (steering & 0xFF);
message = new byte[2];
message[0] = drvByte;
message[1] = steerByte;
msg_length = message.length;
//message = messageStr.getBytes();
try {
DatagramPacket p = new DatagramPacket(message, msg_length,local,server_port);
s.send(p);
}
catch (Exception e) {
// TODO Auto-generated catch block
Log.d("Powerwheelino", e.getStackTrace() +"ERROR ");
e.printStackTrace();
return false;
}
return true;
}
}
Here's the listening UDP server (C++) code
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <SerialStream.h>
using namespace std;
class udp_server {
int sock;
int bytes_read;
socklen_t addr_len;
struct sockaddr_in server_addr , client_addr;
public:
udp_server(int portNum)
{
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portNum);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock,(struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1)
{
perror("Bind");
exit(1);
}
addr_len = sizeof(struct sockaddr);
printf("\nUDPServer Waiting for client on port %d", portNum);
fflush(stdout);
}
int listen(char recv_data[]) {
while (1)
{
bytes_read = recvfrom(
sock,
recv_data,
1024,
0,
(struct sockaddr *)&client_addr,
&addr_len
);
recv_data[bytes_read] = '\0';
printf("\n(%s , %d) said : ",inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
printf("%s", recv_data);
string drive;
string direction;
int speed, angle;
if ((recv_data[0] & 128) > 0) {
drive = "Fwd";
}
else {
drive = "Rev";
}
if ((recv_data[1] & 128) > 0) {
direction = "Left";
}
else {
direction = "Right";
}
speed = recv_data[0] & 127;
angle = recv_data[1] & 127;
printf("\t %s # %d and %s # %d",
drive.c_str(),
speed,
direction.c_str(),
angle);
fflush(stdout);
}
return 0;
}
};
Here's a snippet of the serial communication to the Arduino using LibSerial:
LibSerial::SerialStream myss;
SerialComm(int argc, char** argv) {
myss = new LibSerial::SerialStream("/dev/ttyS0", ios_base::out);
myss.SetBaudRate(LibSerial::SerialStreamBuf::BAUD_57600);
myss.SetCharSize(LibSerial::SerialStreamBuf::CHAR_SIZE_8);
myss.SetFlowControl(LibSerial::SerialStreamBuf::FLOW_CONTROL_NONE);
myss.SetParity(LibSerial::SerialStreamBuf::PARITY_NONE);
myss.SetNumOfStopBits(1);
const int Dsize = 2;
char buffer[1];
buffer[0] = 125; //0b00000001;
buffer[1] = '\0';
bitset(buffer[0]);
//myss << buffer;
myss.write(buffer,1);
//myss.Close();
}
You could use an Arduino with an Ethernet Shield - or possibly a Netduino. Basically, any device with wireless internet capabilities, since that is the only wireless protocol Android uses - besides Bluetooth (or NFC). When the user presses a button, you could open a Socket or a BluetoothSocket to communicate to the second device that it needs to open the switch. Fairly simple - if you have a wireless home network, then your device could be plugged in to your router with a physical wire - as long as your Android device and your microprocessor are on the same network. There might be other wireless options you could use - these are just the simplest I could thing of. Hope this helps!
That's why how I did it with my iPhone (should be the same on Android):
run a TCP server on a computer connected to the same network as your phone and by USB/serial to the Arduino.
This server should forward all incoming data coming through Wi-Fi from your Android phone through USB to the Arduino.
The phone should run a TCP client which sends a simple one-byte (maybe zero and non-zero) command
The Arduino shall be programmed so it listens for incoming serial data via interrupts; if a byte arrives it decides if it should switch the I/O pin on or off.
You can also use a Rugged Circuits Yellowjacket. It has a Wifi on board and can serve simple web pages and control inputs/outputs.
When I call recvfrom using the Android NDK, I get NULL returned to my sockaddr_in from. This same exact code works fine on my desktop environment, but not on the device.
int MyClass::ReceiveData(char *buffer, int bufferLength)
{
int numBytes = 0;
struct sockaddr_in from;
socklen_t fromLength = sizeof(struct sockaddr_in);
numBytes = recvfrom(mConnectionSocket,
buffer,
bufferLength,
0,
(struct sockaddr *)&from,
&fromLength);
if (numBytes == -1)
perror("recvfrom");
int fromAddress = ntohl(from.sin_addr.s_addr);
return fromAddress;
}
Anybody have any ideas?
I get NULL returned to my sockaddr_in 'from'
That's not possible with that code. from isn't a pointer that can become NULL. More probably your sockaddr_in structure named by from is getting zeroed. Which would be caused by using this on a TCP socket. If this is TCP you should be calling getpeername() on the socket to get the peer address.