在两端发送和接收消息

时间:2016-09-25 03:33:42

标签: c sockets client-server

我有以下客户端和服务器代码。

server.c

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

#define MAX_DATA 1024
#define BUFFER 1024

int _GetHostName(char *buffer, int lenght);

const char MESSAGE[]="Hello, World!\n";
const int BACK_LOG=5;

int main(int argc, char *argv[]){
    int serverSocket=0, on=0, port=0, status=0, childPid=0;
    struct hostent *hostPtr=NULL;
    char hostname[80]="";
    char data[MAX_DATA];
    struct sockaddr_in serverName={0};

    char input[BUFFER];
    char output[BUFFER];
    int len;


    if(2!= argc){
        fprintf(stderr, "Usage : %s <port>\n", argv[0]);
        exit(1);
    }
    port=atoi(argv[1]);
    serverSocket=socket(PF_INET,SOCK_STREAM, IPPROTO_TCP);
    if(-1==serverSocket){
        perror("socket()");
        exit(1);
    }

    on=1;
    status=setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
    if(-1==status){
        perror("setsockopt(...,SO_REUSEADDRE,...)");
    }

    {
        struct linger linger={0};
        linger.l_onoff=1;
        linger.l_linger=30;
        status=setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, (const char*)&linger, sizeof(linger));
        if(-1==status){
            perror("setsockopt(...,SO_LINGER,...)");
        }
    }

    status=_GetHostName(hostname, sizeof(hostname));
    if(-1==status){
        perror("_GetHostName()");
        exit(1);
    }

    hostPtr=gethostbyname(hostname);
    if(NULL==hostPtr){
        perror("gethostbyname()");
        exit(1);
    }

    (void)memset(&serverName,0,sizeof(serverName));
    (void)memcpy(&serverName.sin_addr, hostPtr->h_addr,hostPtr->h_length);

    serverName.sin_family=AF_INET;
    serverName.sin_port=htons(port);

    status=bind(serverSocket, (struct sockaddr*)&serverName,sizeof(serverName));
    if(-1==status){
        perror("bind");
        exit(1);
    }


    status=listen(serverSocket, BACK_LOG);
    if(-1==status){
        perror("listen()");
        exit(1);
    }

    for(;;){
        struct sockaddr_in clientName={0};
        int slaveSocket, clientLength=sizeof(clientName);

        (void)memset(&clientName,0,sizeof(clientName));

        slaveSocket=accept(serverSocket,(struct sockaddr*)&clientName, & clientLength);
        if(-1==slaveSocket){
            perror("accept()");
            exit(1);
        }

        childPid=fork();

        switch(childPid){
            case -1:perror("fork()");
            exit(1);
            case 0: close(serverSocket);
            if(-1==getpeername(slaveSocket, (struct sockaddr*)&clientName, &clientLength)){
                perror("getpeername()");
            }else{
                printf("Connection request from %s \n", inet_ntoa(clientName.sin_addr));

                int data_len=1;

                while(data_len){
                    data_len=recv(slaveSocket,data, MAX_DATA,0);
                    if(data_len){
                        //send(slaveSocket,data,data_len,0);

                        data[data_len]='\0';
                        printf("CLIENT: %s", data);

                        printf("SERVER : ");
                        fgets(input,BUFFER, stdin);
                        send(slaveSocket, input, strlen(input),0);
                    }


                }

            }

            printf("Client disconnected\n");
            close(slaveSocket);
            exit(0);
            default:close(slaveSocket);
        }
    }
    return 0;
}

int _GetHostName(char *buffer,int length){
    struct utsname sysname={0};
    int status=0;

    status=uname(&sysname);
    if(-1!=status){
        strncpy(buffer,sysname.nodename,length);
    }
    return(status);
}

client.c

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


#define BUFFER 1024

int main(int argc, char *argv[]){
    int clientSocket, remotePort, status=0;
    struct hostent *hostPtr=NULL;
    struct sockaddr_in serverName={0};
    char buffer[256]="";
    char *remoteHost=NULL;

    char input[BUFFER];
    char output[BUFFER];
    int len;


    if(3!=argc){
        fprintf(stderr, "Usage: %s <serverHost> <serverPort> \n",argv[0]);
        exit(1);
    }
    remoteHost=argv[1];
    remotePort=atoi(argv[2]);
    clientSocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(-1==clientSocket){
        perror("socket()");
        exit(1);
    }

    hostPtr=gethostbyname(remoteHost);
    if(NULL==hostPtr){
        hostPtr=gethostbyaddr(remoteHost,strlen(remoteHost), AF_INET);
        if(NULL==hostPtr){
            perror("Error resolving server address ");
            exit(1);
        }
    }
    serverName.sin_family=AF_INET;
    serverName.sin_port=htons(remotePort);
    (void)memcpy(&serverName.sin_addr,hostPtr->h_addr,hostPtr->h_length);

    status=connect(clientSocket,(struct sockaddr*)&serverName,sizeof(serverName));
    if(-1==status){
        perror("connect()");
        exit(1);
    }

    while(1){
        printf("CLIENT: ");
        fgets(input,BUFFER, stdin);
        send(clientSocket, input, strlen(input),0);

        len=recv(clientSocket, output,BUFFER, 0);
        output[len]='\0';
        printf("SERVER : %s\n",output);
    }
    close(clientSocket);


}

上面的服务器代码可以从客户端接收和发送消息。客户端还可以从服务器接收消息并向服务器发送消息。但是,他们一次只能发送一条消息。在客户端可以发送更多消息之前,需要先等待服务器发送单个消息。与服务器相同。 如何让他们接收和发送多条消息而无需等待另一方回复?

enter image description here

2 个答案:

答案 0 :(得分:1)

我的理解是,您希望继续发送而无需等待服务器的响应。

实现它的一种简单方法是使用poll()函数首先检查任何响应。只有当您确定要读取数据时,才会致电recv()

int pollForData(int sock) {
    struct pollfd pollSock;
    pollSock.fd = sock;
    pollSock.events = POLLIN;
    return  poll(&pollSock, 1, 10);
}

答案 1 :(得分:1)

在套接字和stdin上使用select(),并从两者中的任何一个进行读取/接收。如果读取完成,则写入/发送到stdout或插座。

在服务器“套接字”中将引用接受套接字,在客户端中引用已连接的套接字。

无关,但仍然很重要:

char data[MAX_DATA];

...

data_len=recv(slaveSocket,data, MAX_DATA,0);
if(data_len){
  data[data_len]='\0';

...

可能会在收到MAX_DATA个字节时导致缓冲区溢出,因此0将在data的末尾写入1。

要修复此定义data,请执行以下操作:

char data[MAX_DATA + 1];

所有代码完全错过了对recv()send()的调用的错误检查。这很糟糕。