2016-08-03 9 views
1

クライアントとクライアントの間のサーバーとの通信を実装しようとしました。サーバーの機能は、クライアントがクライアントAがサーバーにメッセージを送信すると仮定した場合、サーバーはそのメッセージを他のクライアント、つまりクライアントBに転送する必要があります。クライアントBがサーバーにメッセージを送信するのと同じ方法で、このプログラムには2つのクライアントしか関係しません。クライアントAから受信したメッセージが、私はこの問題は、受信の保存によるものだと思うクライアントBに転送されるとき クライアントのクライアントとの通信で、select()関数を使用して

Socket Operation on Non-socket 

が、私はこのエラーを取得する:私は、コードを実行したときに私が手 エラーは、それが言うことですクライアントBのアドレスをクライアントAのアドレスに変更します。これについてはわかりません。

これまでのサーバーコード。

#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つのクライアントのみを必要とします。あなたが他のいくつかの改善点を指摘できるかどうか本当に感謝しています。

+2

エラーが発生した場合は、実行されなかったかのように処理を進めることは許されません。それらの 'perror()'呼び出しのそれぞれには、クリーンアップとリターンが続くべきです。 – EJP

+1

クライアントソケットは 'clientsocks'にどのように格納されますか? – immibis

+0

@EJPあなたはループを破って帰るべきだということですか? –

答えて

1

実際に修正するStackOverflowメンバーの仕事ではないいくつかの構造的な問題があります。

  1. 各クライアントが同じソケットまたは独自の一意のソケットに接続するかどうかを判断します。
  2. もしあなたが共有接続をしていると思われたら...そして共有接続によって、あなたは1つのポートでリッスンし、複数の受け入れをしているということです。あなたがポートから何らかのデータを読むまで。次の場合、あなたが知っているように、各クライアントは、経由いくつかの情報を送信する必要があります接続し、次にBまたはBが接続されている場合、次にA.あなたが忘れてしまったようなあなたのsetsockopt周りのコードは思わ
  3. {}
  4. clientsocksあなたを節約どのアレイスロットを使用するかを決定するためにクライアントからの情報を使用することができます。たぶんあなたは100のクライアントを持っていて、それぞれが接続してから32ビットワード(クライアント番号が1〜100の間)を送信します。
  5. さまざまなクライアントからメッセージを読み込むことができたら(おそらく今のところ印刷して何が起こっているかを確認したいと思うかもしれません)、さまざまなメッセージを作成できます。目標は、クライアントAがクライアントBの連絡先情報をサーバーに要求して、AがBに直接接続し、Bにメッセージを送信できるようにすることです。
  6. または#5の代わりに、クライアント26は、クライアント45用であることを示すメッセージをサーバーに送信できる必要があり、サーバーはチェックインしたクライアントの配列を確認してからメッセージを送信できるはずですアレイスロット45のクライアントに送信します。
  7. クライアントには、クライアントIDをクライアントアレイソケットにマップする方法があるため、固有のID /番号が必要です。
  8. これらのエラーの一部は、サーバーを終了させるよりも直接処理する方が効果的です。ソケットインデックスに関連付けられたソケットを閉じてエラーを引き起こす可能性があります。エラーメッセージには、エラーの原因となったクライアント/ソケットインデックスを示す必要があります。一般的に、メッセージにはより多くのデバッグメッセージと詳細情報が必要です。
+0

遅く返事を申し訳ありません。しかし、それは素晴らしい答えです。私は何かを尋ねるときにそれらの事を世話します。 –

関連する問題