Работать с сокетами на низком уронде в Андроиде (т.е. на ядре линукс) можно с помощью следующего набора заклинаний.
#define WIN32 // заголовки стандартного C #include <string.h> #include <stdio.h> // подключаем заголовки для разных OS #if defined WIN32 #include <winsock.h> // WinSock #elif defined LINUX #include <unistd.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #endif // переопределяем некоторые типы и константы // в зависимости от OS #if defined WIN32 typedef int socklen_t; // размер сокета в Unix #elif defined LINUX typedef int SOCKET; #define INVALID_SOCKET -1 // костанта WinSock #define SOCKET_ERROR -1 // стандартная ошибка WinSock // WinSock, в отличие от Unix, не использует файл-дескрипторы // поэтому переопределяем наименование метода #define closesocket(s) close(s); #endif int init_sockaddr_in(char *hostname, struct sockaddr_in *sin); int client_process(int fd, char *hostname); int send_request(int fd, char *hostname); int recv_reply(int fd); int main() { struct sockaddr_in server; SOCKET sockfd; int recvMsgSize; // имя сервера, может быть вида "www."""".com" и т.д. char * srv = "localhost"; #if defined WIN32 // для Windows мы должны инициализировать Winsock WSADATA wsa_data; WSAStartup(MAKEWORD(1,1), &wsa_data); #endif // создаем сокет sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(sockfd == INVALID_SOCKET) { perror("Could not create socket.\n"); return(SOCKET_ERROR); } // пробуем создать метаданные сервера recvMsgSize = init_sockaddr_in(srv, &server); if(recvMsgSize < 0) { perror("Could not initialize address.\n" ); return(SOCKET_ERROR); } // пытаемся соединиться через сокет recvMsgSize = connect(sockfd, (struct sockaddr*)&server, sizeof(server)); if(recvMsgSize < 0) { perror("Error while connecting to server.\n"); return(SOCKET_ERROR); } // посылаем сообщения на сервер и принимаем респонс recvMsgSize = client_process(sockfd, srv); printf("Program has ended successfully."); #if defined WIN32 // для Windows мы должны явно указать, что завершаем работу Winsock WSACleanup(); #endif return 0; } int init_sockaddr_in(char *hostname, struct sockaddr_in *sin) { struct servent *serv; // утсанавливаем поинтер в памяти memset(sin, 0, sizeof(*sin)); sin->sin_family = AF_INET; // проверяем, в каком виде записан адрес сервера: IP или "www.****.com" #if defined LINUX if( !inet_aton( hostname, &sin->sin_addr ) ) #endif { // если запись в виде "www.****.com", ищем IP адрес struct hostent *host = gethostbyname(hostname); if(!host) return SOCKET_ERROR; sin->sin_addr.s_addr = *(unsigned long*)host->h_addr_list[0]; } // получаем дефолтный порт для выбранного протокола serv = getservbyname("http", "tcp"); if(!serv) return SOCKET_ERROR; sin->sin_port = serv->s_port; return EXIT_SUCCESS; } int client_process(int socketId, char *hostname) { // посылаем данные printf("Sending...\n"); if(send_request(socketId, hostname)) { // неудачно скастовали заклинание return SOCKET_ERROR; } // получаем ответ от сервера printf("Receiving reply...\n"); if(recv_reply(socketId)) { // ошибка магии return SOCKET_ERROR; } return EXIT_SUCCESS; } int send_request(int fd, char *hostname) { // здесь мы должны сформировать запрос к серверу // запрос должен содержать стандартные заголовки и константы // типа таких: "GET /foo/bar/baz/ HTTP/1.1\r\nHost: www.myfoo.com Connection: close" // char format[150] = "GET /foo/bar/baz/ HTTP/1.1\r\nHost: "; int length = 0; int ret = 0; strcat(format, hostname); strcat(format, "\r\nConnection: close\r\n\r\n"); length = strlen(format); // посылаем запрос format длиной length через сокет fd ret = send(fd, format, length, 0); if(ret != length ) return SOCKET_ERROR; return EXIT_SUCCESS; } int recv_reply(int fd) { fd_set readfds; // определяем буффер для входящих данных char buf[256]; int length; while(1) { // инициализируем буффер FD_ZERO(&readfds); FD_SET(fd, &readfds); memset(buf, 0, sizeof(buf)); // ждем прибытия данных с сервера if(select(fd+1, &readfds, NULL, NULL, NULL) < 0 ) { // ошибочка в заклинании return SOCKET_ERROR; } // проверяем, если ли в дескрипторе переданные данные if(FD_ISSET(fd, &readfds)) { // получаем их length = recv(fd, buf, sizeof(buf)-1, 0); if(length < 0) return SOCKET_ERROR; else if(length == 0) // данные закончились break; // вываливаем полученный буфер куда хотим printf("%s\n", (char*)buf); } } return EXIT_SUCCESS; }
Немного примечаний к волшебству.
Отношения с сокетами на этом уровне примерно одинаковые в Linux и в Windows. Я по долгу работы и в силу личных предпочтений пишу код в Windows (и чтобы не запусать лишний раз ресурсоемкий билд). Для этого в коде введен переключатель для определения условия компиляции. При отсутствии необходимости в нем, его легко можно удалить и компилироваться исключительно под выбранную ОС.