客户端到客户端通信使用c选择()函数 [英] Client to Client communication using select() function in c

查看:101
本文介绍了客户端到客户端通信使用c选择()函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是想实现一个客户端到客户端通信与服务器之间。服务器的功能是,当客户端假设客户端A将消息发送到服务器,服务器应当客户端B发送消息给它应该转发服务器转发消息给其他客户端,客户端B.相同方式给客户A.该方案只涉及两个客户端。
当我执行code我得到的错误是,它说:

 非插槽Socket操作

我得到这个错误时,从客户端A接收到的消息转发到客户端B.我认为这个问题是由于客户端B收到的地址给客户A的,我不知道该地址存储。


  

我的服务器code为止。


 的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;
#包括LT&; netinet / in.h中>
#包括LT&; SYS / socket.h中>
#包括LT&; SYS / types.h中>
#包括LT&; ARPA / inet.h>
#包括LT&;&signal.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&;&errno.h中GT;
#包括LT&; SYS / time.h中>
#定义SERVER_PORT 5009
诠释主(){
unsigned int类型的sockfd,C,C1,C2,clientlen,clientfd;
结构SOCKADDR_IN服务器;
结构SOCKADDR_IN客户端1;
INT clientsocks [2];
炭rmsg1 [100],MSG1 [100],rmsg2 [100],MSG2 [100];
烧焦w_msg [] =连接到服务器建立;FD_SET readfds; //为临时文件描述符列表。clientsocks [0] = 0;
clientsocks [1] = 0;
//套接字创建过程。
的sockfd =插座(AF_INET,SOCK_STREAM,0);
如果(的sockfd℃,){
    PERROR(插座无法创建);
}//对于重用插座。
INT在= 1;
如果(setsockopt的(的sockfd,SOL_SOCKET,SO_REUSEADDR,&放大器;上,的sizeof(上))小于0)
//套接字地址
bzero((字符*)及服务器的sizeof(服务器));
server.sin_family = AF_INET; // IPv4的Internet协议
INET_ATON(127.0.0.1,&安培; server.sin_addr);
server.sin_port = htons(SERVER_PORT);//绑定套接字来解决。
如果(绑定(的sockfd,(结构sockaddr *)及服务器的sizeof(服务器))小于0){
    PERROR(绑定错误);
    出口(EXIT_FAILURE);
}//监听接受连接。
如果(听(的sockfd,SOMAXCONN)小于0){
    PERROR(错误监听);
    出口(EXIT_FAILURE);
}无符号整型new_sock;
clientlen = sizeof的(客户端1);
INT活动;
而(1){    //清除插座集。
    FD_ZERO(安培; readfds);    //添加主的sockfd到插座集。
    FD_SET(的sockfd,&安培; readfds);
    unsigned int类型max_sd =的sockfd;    //添加子插座设置。
    对(INT I = 0; I&2;我++){
           C = clientsocks [I]
        如果(c取代; 0)
            FD_SET(C,&安培; readfds);
        如果(c取代; max_sd)
            max_sd = C;
    }    活性=选择(max_sd + 1,&安培; readfds,NULL,NULL,NULL);
    如果(活动℃,){
        PERROR(错误的选择());
        出口(EXIT_FAILURE);
    }    //当有事的sockfd传入连接。
    如果(FD_ISSET(的sockfd,&安培; readfds)){
        new_sock =接受(的sockfd,(结构sockaddr *)及客户端1,&安培; clientlen);
        如果(new_sock大于0){
            对(INT I = 0; I&2;我++){
                如果(clientsocks [I] == 0){
                    clientsocks [I] = new_sock;
                    打破;
                }
            }
        }
        如果(new_sock℃,){
            PERROR(错误接受);
            出口(EXIT_FAILURE);
        }
        如果(发送(new_sock,w_msg,strlen的(w_msg),0)!=的strlen(w_msg)){
            PERROR(欢迎信息);
            出口(EXIT_FAILURE);
        }
    C1 = clientsocks [0];
    C2 = clientsocks [1];
    FD_SET(C1,&放大器; readfds);
    FD_SET(C2,&放大器; readfds);
    }    //否则,如果它不是一个新的传入连接。
    如果(FD_ISSET(C1,&放大器; readfds)){
        如果(的recv(C1,rmsg1,100,0)℃,){
            PERROR(接收1);
            出口(EXIT_FAILURE);
        }
        输出(客户端1>>%S \\ n,rmsg1);
        //转发给客户端B.
        如果(发送(C2,rmsg1,100,0)℃,){
            PERROR(错误转发到2);
            出口(EXIT_FAILURE);
        }
    }
    如果(FD_ISSET(C2,&放大器; readfds)){
        如果(的recv(C2,rmsg2,100,0)℃,){
            PERROR(接收2);
            出口(EXIT_FAILURE);
        }
        输出(客户机2>>%S \\ n,rmsg2);
        如果(发送(C1,rmsg2,100,0)℃,){
            PERROR(错误转发至1);
            出口(EXIT_FAILURE);
        }
    }
}
接近(的sockfd);
返回1;
}

我的问题只涉及两个客户端。我真的AP preciate如果你能指出一些其他的改进还。


解决方案

您已经有了一些结构性的问题,是不是真的计算器成员的工作来解决。


  1. 确定是否每个客户端都连接到同一个插座或自己独特的插座连接,因此听。

  2. 如果您有一个共享的连接,看来你是去为...和共享连接我的意思是,你正在听一个端口上,并进行多次接受,然后发出后接受你不能假设谁已连接直到你从端口读取一些数据。你应该有每个客户端通过发送一些信息,让你知道,如果一个连接,然后B或在B相连,那么A。

  3. 在你的setsockopt的code好像你忘了{}

  4. 在保存clientsocks你可以使用这些信息从客户端确定要使用的阵列插槽。也许你有100个客户,他们每一个连接,然后发送32位字(其中包含他们的客户号,1-100之间)。

  5. 一旦你可以阅读来自不同客户端的消息(可能要打印出来,现在所以你可以看到发生了什么),你可以建立在各种消息。我们的目标是为客户端A可以向服务器客户端B的联系信息,以便可以直接连接到B,发送B中的消息。

  6. 或,而不是#5,客户端26应能够将消息发送到服务器,指示其是用于客户端45和服务器应当能够检查在已经检查客户的数组,然后发送该消息在阵列槽45客户端。

  7. 客户需要有唯一的ID /号码,使服务器有一个方法来映射客户端ID对clientarray插座。

  8. 其中有些错误是更好的直接处理不是使服务器退出。也许你可以关闭与插座指数造成错误关联的插座。你的错误信息应该指出的客户端/插座指数造成错误。你,在一般情况下,需要更多的调试消息,并在消息的详细信息。

I was trying to implement a client to client communication with a server in between them. The function of the server is that when a client suppose Client A sends a message to the server, the server should forward that message to the other client, Client B. Same way when the Client B sends a message to the server it should be forwarded to Client A. This programs involves only two clients. The error I get when I execute the code is that it says:

Socket Operation on Non-socket

I get this error when the received message from Client A is forwarded to Client B. I think the issue is due to the storing of received address of Client B to the address of Client A. I'm not sure about that.

My server code so far.

#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;
}

My problem involves two clients only. I would really appreciate if you could point out some other improvements also.

解决方案

You've got some structural problems that isn't really the job of StackOverflow members to fix.

  1. Decide if each client is going to connect on the same socket or their own unique socket, listen accordingly.
  2. If you have a shared connection, which it seems you are going for... and by shared connection I mean you are listening on one port and doing multiple accepts, then after a given accept you can't assume who has connected until you read some data from the port. You should have each client send some information through, so that you know if A connected and then B or if B connected and then A.
  3. The code around your setsockopt seems like you forgot {}
  4. When saving the clientsocks you can use the information from the client to determine which array slot to use. Maybe you have 100 clients and they each connect and then send a 32 bit word (which contains their client number, between 1-100).
  5. Once you can read messages from various clients (probably want to print them out for now so you can see what is happening), you can build in various messages. The goal is for client A to be able to ask the server for the contact information of client B so that A can directly connect to B and send B a message.
  6. OR, instead of #5, Client 26 should be able to send a message to the server, indicating its is for client 45 and the server should be able to check the array of clients that have checked in and then send the message to the client in array slot 45.
  7. Clients need to have unique ID/numbers so the server has a way to map the client ID's to clientarray sockets.
  8. Some of those errors are better handled directly than causing the server to exit. Maybe you can close the socket associated with the socket index causing the error. Your error messages should indicate which client/socket index caused the error. You, in general, need more debug messages and more information in the messages.

这篇关于客户端到客户端通信使用c选择()函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆