使用accept接收顺序数据

时间:2014-09-05 17:59:53

标签: c sockets networking

我试图在两个电台(A和B)之间建立通信。 A应该向B发送多个数据(反之亦然):"多个数据"意味着我想在一个接受会话中使用来自两个站的发送 recv 。目前,我只是尝试每个连接发送超过1个数据包。由于我不熟悉处理套接字,我很难理解套接字背后的概念。在下面的代码中,接收器成功检索发送的第一个 int 发送器,但不是以下代码。你能告诉我我做错了吗?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>

#define DATA_TO_SEND_LENGTH 9
#define PRINT_ERRNO_EXIT(who,id) { \
        int verrno=errno; \
        printf("%s ERRNO: %d\nexit id: %d\n",who==0?"sender":"receiver",verrno,id); \
        return id; \
}

int main(){
    char* ipaddress="127.0.0.1";
    int portNumber=12345;
    int socketOptionalValue=1;
    const int dataToSend[]={1,2,3,4,5,6,7,8,9};

    if (fork()==0){
        // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        // @@@@@@@@@@@@@@@ CHILD: HE IS THE SENDER @@@@@@@@@@@@@@@@
        // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        int socketSenderDescriptor;
        struct sockaddr_in destinationInfos;
        struct sockaddr_in tmp;
        int i;
        // ************** CREATE AND OPEN THE SOCKET *****************

        inet_aton(ipaddress,&tmp.sin_addr);
        socketSenderDescriptor = socket(AF_INET, SOCK_STREAM, 0); // socket file descriptor
        if (socketSenderDescriptor < 0 ){
            PRINT_ERRNO_EXIT(0,1);
        }
        if (setsockopt(socketSenderDescriptor,SOL_SOCKET,SO_REUSEADDR,&socketOptionalValue,sizeof(socketOptionalValue))!=0){
            PRINT_ERRNO_EXIT(0,2);
        }
        if (setsockopt(socketSenderDescriptor,SOL_SOCKET,SO_KEEPALIVE,&socketOptionalValue,sizeof(socketOptionalValue))!=0){
            PRINT_ERRNO_EXIT(0,2);
        }
        memset(&destinationInfos,0,sizeof(destinationInfos)); //clean the structure used to store destination information
        destinationInfos.sin_family=AF_INET; //we want to use inet class
        destinationInfos.sin_addr.s_addr=tmp.sin_addr.s_addr;//Set destination IP
        destinationInfos.sin_port=htons(portNumber); //communiction port number
        //connection
        if (connect(socketSenderDescriptor,(struct sockaddr *)&(destinationInfos),sizeof(destinationInfos)) < 0){
            PRINT_ERRNO_EXIT(0,3);
        }
        // ******************* SEND DATA **********************
        sleep(1); //wait for the parent to start listening...
        for (i=0;i<DATA_TO_SEND_LENGTH;i++){
            printf("sender: i'm sending %d\n",dataToSend[i]);
            send(socketSenderDescriptor,&(dataToSend[i]),sizeof(dataToSend[i]),0);
            sleep(1);
        }
        // ******************* CLOSE SOCKET *******************
        if (close(socketSenderDescriptor)!=0){
            PRINT_ERRNO_EXIT(0,4);
        }
        printf("SENDER FINISH!\n");
        return EXIT_SUCCESS;
    }else {
        // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        // @@@@@@@@@@@@@@@@ PARENT: HE IS THE RECEIVER @@@@@@@@@@@@
        // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        struct sockaddr_in remoteSocketInfos;
        struct sockaddr_in localSocketInfos;
        int localSocketDescriptor;
        int sessionSocket;
        int valueReceived;
        int i=0;
        static socklen_t socksize=sizeof(struct sockaddr_in);
        // ******************* CREATE AND BIND THE SOCKET ******************
        //write inside localSocketInfos the information about our server
        memset(&localSocketInfos,0,sizeof(localSocketInfos));
        localSocketInfos.sin_family=AF_INET;
        localSocketInfos.sin_addr.s_addr=htonl(INADDR_ANY);
        localSocketInfos.sin_port= htons(portNumber);

        //create the main socket where all connection to our server will be received
        localSocketDescriptor=socket(AF_INET,SOCK_STREAM,0);
        if (localSocketDescriptor<0){
            PRINT_ERRNO_EXIT(1,1);
        }
        //On Linux, SO_REUSEADDR allows you to bind to an address unless an active connection is present
        //see https://stackoverflow.com/questions/4979425/difference-between-address-in-use-with-bind-in-windows-and-on-linux-errno
        setsockopt(localSocketDescriptor,SOL_SOCKET,SO_REUSEADDR,&socketOptionalValue,sizeof(socketOptionalValue));
        //Bind our socket to the socketDescription: this allows the machine to know the data
        //received on the port specified in the sockaddr_in should be handled by our specified socket.
        if (bind(localSocketDescriptor,(struct sockaddr*)&localSocketInfos,sizeof(struct sockaddr))!=0){
            PRINT_ERRNO_EXIT(1,2);
        }
        //tells our program to start listening the socket we have created. This will NOT block the flow of the program because
        //we are not waiting anything at all.
        if (listen(localSocketDescriptor,10)!=0){
            PRINT_ERRNO_EXIT(1,3);
        }
        // ************************ WAIT FOR CONNECTIONS ********************
        do {
            i++;
            printf("Waiting transmission on %s, port %d...\n",inet_ntoa(localSocketInfos.sin_addr),localSocketInfos.sin_port);
            sessionSocket=accept(localSocketDescriptor,(struct sockaddr*)&remoteSocketInfos,&socksize);
            if (sessionSocket<0){
                int verrno=errno;
                printf("receiver ERRNO: %d\n",verrno);
                continue;
            }
            printf("Incoming transmission from %s, port %d...\n",inet_ntoa(remoteSocketInfos.sin_addr),remoteSocketInfos.sin_port);
            recv(sessionSocket,&valueReceived,sizeof(valueReceived),0);
            printf("DATA READ! %d\n",valueReceived);
            close(sessionSocket);
        } while(i<DATA_TO_SEND_LENGTH);
        if (close(localSocketDescriptor)==0){
            PRINT_ERRNO_EXIT(1,4);
        }
        printf("RECEIVER FINISH!\n");
        return EXIT_SUCCESS;
    }
}

我也发布了我的程序输出,希望它可以帮助你找到我做错的事情:

Waiting transmission on 0.0.0.0, port 14640...
Incoming transmission from 127.0.0.1, port 63718...
sender: i'm sending 1
DATA READ! 1
Waiting transmission on 0.0.0.0, port 14640...
sender: i'm sending 2
sender: i'm sending 3
sender: i'm sending 4
sender: i'm sending 5
sender: i'm sending 6
sender: i'm sending 7
sender: i'm sending 8
sender: i'm sending 9
SENDER FINISH!

1 个答案:

答案 0 :(得分:1)

在接收者流程中,accept()只需要调用一次。由于您将accept()置于while循环内,因此在accept上将阻止循环的第二次迭代,因为没有新连接进入。

一个简单的解决方法是将accept放在循环之外。您可以尝试以下修复程序,看看它是否有效。请注意,循环后也会移动close

    // ************************ WAIT FOR CONNECTIONS ********************
    printf("Waiting transmission on %s, port %d...\n",inet_ntoa(localSocketInfos.sin_addr),localSocketInfos.sin_port);
    sessionSocket=accept(localSocketDescriptor,(struct sockaddr*)&remoteSocketInfos,&socksize);
    if (sessionSocket<0){
        int verrno=errno;
        printf("receiver ERRNO: %d\n",verrno);
        PRINT_ERRNO_EXIT(1,5);
    }
    do {
        i++;
        printf("Incoming transmission from %s, port %d...\n",inet_ntoa(remoteSocketInfos.sin_addr),remoteSocketInfos.sin_port);
        recv(sessionSocket,&valueReceived,sizeof(valueReceived),0);
        printf("DATA READ! %d\n",valueReceived);
    } while(i<DATA_TO_SEND_LENGTH);
    close(sessionSocket);