2016-08-03 2 views
1

Я пытался реализовать взаимодействие клиента с клиентом с сервером между ними. Функция сервера заключается в том, что, когда клиент полагает, что клиент A отправляет сообщение серверу, сервер должен отправить это сообщение другому клиенту, клиенту B. То же самое, когда клиент B отправляет сообщение на сервер, он должен быть переадресован к клиенту А. Эти программы включают только двух клиентов. Я получаю ошибки, когда я выполняю код является то, что он говорит:Связь клиента с клиентом с помощью функции select() в c

Socket Operation on Non-socket 

Я получаю эту ошибку, когда получил сообщение от клиента A пересылается клиент B. Я думаю, что проблема связана с хранением полученного адрес клиента B по адресу клиента А. Я не уверен в этом.

Код моего сервера до сих пор.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <arpa/inet.h> 
#include <signal.h> 
#include <unistd.h> 
#include <errno.h> 
#include <sys/time.h> 
#define SERVER_PORT 5009 


int main(){ 
unsigned int sockfd, c,c1,c2, clientlen, clientfd; 
struct sockaddr_in server; 
struct sockaddr_in client1; 
int clientsocks[2]; 
char rmsg1[100], msg1[100],rmsg2[100], msg2[100]; 
char w_msg[] = "Connection to server established"; 

fd_set readfds; // For temp file descriptor list. 

clientsocks[0] = 0 ; 
clientsocks[1] = 0 ; 
//Socket Creation Process. 
sockfd = socket(AF_INET, SOCK_STREAM, 0); 
if(sockfd < 0){ 
    perror("Socket cannot be created"); 
} 

//For reusing the socket. 
int on = 1; 
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
//Socket address 
bzero((char *) &server, sizeof(server)); 
server.sin_family = AF_INET; // IPv4 internet Protocols 
inet_aton("127.0.0.1", &server.sin_addr); 
server.sin_port = htons(SERVER_PORT); 

//Binding socket to address. 
if (bind(sockfd, (struct sockaddr*)&server, sizeof (server)) < 0){ 
    perror("Bind Error"); 
    exit(EXIT_FAILURE); 
} 

//Listen to accept connection. 
if(listen(sockfd, SOMAXCONN) < 0){ 
    perror("Error in Listen"); 
    exit(EXIT_FAILURE); 
} 

unsigned int new_sock; 
clientlen =sizeof(client1); 
int activity; 
while(1){ 

    //Clear socket set. 
    FD_ZERO(&readfds); 

    //Adding main sockfd to the socket set. 
    FD_SET(sockfd, &readfds); 
    unsigned int max_sd = sockfd; 

    //Add child sockets to set. 
    for(int i=0 ; i<2; i++){ 
      c = clientsocks[i]; 
     if(c > 0) 
      FD_SET(c, &readfds); 
     if(c > max_sd) 
      max_sd = c; 
    } 

    activity = select(max_sd + 1, &readfds, NULL, NULL, NULL); 
    if(activity < 0){ 
     perror("Error in select()"); 
     exit(EXIT_FAILURE); 
    } 

    //Incoming connection when something happens on sockfd. 
    if(FD_ISSET(sockfd, &readfds)){ 
     new_sock = accept(sockfd, (struct sockaddr *) &client1, &clientlen); 
     if(new_sock > 0){ 
      for(int i=0; i<2; i++){ 
       if(clientsocks[i] == 0){ 
        clientsocks[i] = new_sock; 
        break; 
       } 
      } 
     } 
     if( new_sock < 0){ 
      perror("Error Accepting"); 
      exit(EXIT_FAILURE); 
     } 
     if(send(new_sock, w_msg, strlen(w_msg), 0) != strlen(w_msg)){ 
      perror("Welcome message"); 
      exit(EXIT_FAILURE); 
     } 
    c1 = clientsocks[0]; 
    c2 = clientsocks[1]; 
    FD_SET(c1, &readfds); 
    FD_SET(c2, &readfds); 
    } 

    //Else if its not a new incoming connection. 
    if(FD_ISSET(c1, &readfds)){ 
     if(recv(c1, rmsg1, 100, 0) < 0){ 
      perror("Receive 1"); 
      exit(EXIT_FAILURE); 
     } 
     printf("Client1 >> %s\n", rmsg1); 
     //Forwarding to Client B. 
     if(send(c2, rmsg1, 100, 0) < 0){ 
      perror("Error forwarding to 2"); 
      exit(EXIT_FAILURE); 
     } 
    } 
    if(FD_ISSET(c2, &readfds)){ 
     if(recv(c2, rmsg2, 100, 0) < 0){ 
      perror("Receive 2"); 
      exit(EXIT_FAILURE); 
     } 
     printf("Client2 >> %s\n", rmsg2); 
     if(send(c1, rmsg2, 100, 0) < 0){ 
      perror("Error Forwarding to 1"); 
      exit(EXIT_FAILURE); 
     } 
    } 
} 
close(sockfd); 
return 1; 
} 

Моя проблема состоит из двух клиентов только. Я был бы очень признателен, если бы вы могли указать на некоторые другие улучшения.

+2

Если вы получили сообщение об ошибке, не допустимо, чтобы выполнение выполнялось так, как будто этого не произошло. Каждый из этих вызовов 'perror()' должен сопровождаться очисткой и возвратом. – EJP

+1

Как клиентские сокеты хранятся в 'clientsocks'? – immibis

+0

@EJP Вы имеете в виду, что я должен разорвать петлю и вернуться? –

ответ

1

У вас есть некоторые проблемы с конструкцией, которые не являются задачей членов StackOverflow для исправления.

  1. Решите, будет ли каждый клиент подключаться к одному сокету или к своему уникальному сокету, послушайте его.
  2. Если у вас есть общее соединение, которое, как вам кажется, вы собираетесь ... и по совместному соединению, я имею в виду, что вы слушаете один порт и делаете несколько прием, затем после данного приема вы не можете предположить, кто подключился пока вы не прочитаете некоторые данные из порта. Вам нужно, чтобы каждый клиент отправил некоторую информацию, чтобы вы знали, что A подключен, а затем B, или если B подключен, а затем A.
  3. Код вокруг вашего setsockopt кажется, что вы забыли {}
  4. При сохранении клиентов, вы может использовать информацию от клиента, чтобы определить, какой слот массива использовать. Возможно, у вас 100 клиентов, и каждый из них подключается, а затем отправляет 32-битное слово (которое содержит их номер клиента, между 1-100).
  5. После того, как вы сможете читать сообщения от разных клиентов (возможно, хотите распечатать их сейчас, чтобы вы могли видеть, что происходит), вы можете создавать различные сообщения. Цель заключается в том, чтобы клиент A мог запросить сервер для контактной информации клиента B, чтобы A мог напрямую подключиться к B и отправить сообщение B.
  6. ИЛИ, вместо # 5, клиент 26 должен иметь возможность отправлять сообщение на сервер, указывая, что он предназначен для клиента 45, и сервер должен иметь возможность проверять массив клиентов, которые зарегистрировались, а затем отправить сообщение для клиента в слоте массива 45.
  7. Клиенты должны иметь уникальные идентификаторы/номера, чтобы у сервера был способ сопоставить идентификаторы клиента с клиентскими сокетами.
  8. Некоторые из этих ошибок лучше обрабатываются напрямую, чем выключение сервера. Возможно, вы можете закрыть сокет, связанный с индексом сокета, вызывающим ошибку. В сообщениях об ошибках должно указываться, какой индекс клиент/сокет вызвал ошибку. Вам, в общем, нужно больше сообщений отладки и больше информации в сообщениях.
+0

Извините за поздний ответ. Но это удивительный ответ. Позаботьтесь об этом в следующий раз, когда я что-то спрошу. –