开发者

c program client server

I have written a client and server c program, which I have taken from example code.

I want to write a iterative client and server program, i.e. after client send a string, then the server print that string and then send back a string to client

then the client print the string inputted by server, and so on until the client input 'exit' to quit.

I have modified the code that the client and server is iterative

also, if client input 'exit', the program will quit

But I have a question, I don't know how to make the client to receive the string which is inputed by server, I only can make the server to receive the client's string

Please feel free to provide hints

Many thanks!

my code

client.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <winsock2.h>

#define SA struct sockaddr
#define S_PORT 4321
#define BufferStoreLEN 1024

void errexit(const char *format, ...)
{
        va_list args;
        va_start(args, format);
        vfprintf(stderr, format, args);
        va_end(args);
        WSACleanup();
        exit(1);
}

int main(int argc, char **argv)
{
        WSADATA wsadata;
        SOCKET sockfd, listenfd, connfd;
        int i, n, q, len, alen, out;
        char str[BufferStoreLEN+1];
        char cmp[] = "exit";
        char* BufferStore;
        struct sockaddr_in servaddr, cliaddr;

        if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0)
                errexit("WSAStartup failed\n");

        if (argc != 2)
                errexit("wrong arg");

        if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET )
                errexit("socket error: error number %d\n", WSAGetLastError());

        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(S_PORT);
        if ( (servaddr.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE)
                errexit("inet_addr error: error number %d\n", WSAGetLastError());

        if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) == SOCKET_ERROR)
                errexit("connect error: error number %d\n", WSAGetLastError());

        do {
                printf("Input: ");
                scanf("%s", str);
                out = htonl(strlen(str));
                BufferStore = malloc(strlen(str));
                for( i=0; i<strlen(str); i++)
                        BufferStore[i] = str[i];
                out = send(sockfd, BufferStore, strlen(str), 0);
/*              
                if ( strcmp( cmp, str ) != 0 )
                {
                        printf("Server's response:\n");
                        n = recv(connfd, BufferStore, BufferStoreLEN, 0);

                        while (n > 0) {
                                BufferStore[n] = '\0';
                                printf("%s\n", BufferStore);
                                n = recv(connfd, BufferStore, BufferStoreLEN, 0);
                        } 
                }*/
    开发者_如何学JAVA    }while(strcmp(cmp,str)!=0);

        closesocket(sockfd);
        WSACleanup();
        free(str);
        free(BufferStore);
        return 0;
}

server.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <winsock2.h>
#include <Windows.h>
#define SA struct sockaddr
#define MAXLINE 4096
#define S_PORT 4321
#define BufferStoreLEN 1024

void errexit(const char *format, ...)
{
        va_list args;
        va_start(args, format);
        vfprintf(stderr, format, args);
        va_end(args);
        WSACleanup();
        exit(1);
}

int main(int argc, char **argv)
{

        WSADATA wsadata;
        SOCKET listenfd, connfd;
        SOCKET sockfd;
        int number, out;
        int i, n, q, alen;
        struct sockaddr_in servaddr, cliaddr;
        char BufferStore[BufferStoreLEN+1];
        char* Store;
        char str[BufferStoreLEN+1];
        int flag = 1;

        if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0)
                errexit("WSAStartup failed\n");

        listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd == INVALID_SOCKET)
                errexit("cannot create socket: error number %d\n", WSAGetLastError());

        memset(&servaddr, 0, sizeof(servaddr)); 
        servaddr.sin_family      = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port        = htons(S_PORT);

        if (bind(listenfd, (SA *) &servaddr, sizeof(servaddr)) == SOCKET_ERROR)
                errexit("can't bind to port %d: error number %d\n", S_PORT, WSAGetLastError());

        if (listen(listenfd, 5) == SOCKET_ERROR)
                errexit("can't listen on port %d: error number %d\n", S_PORT, WSAGetLastError());

        if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET )
                errexit("socket error: error number %d\n", WSAGetLastError());

        for ( ; ; ) 
        {
                alen = sizeof(SA);
                connfd = accept(listenfd, (SA *) &cliaddr, &alen);
                if (connfd == INVALID_SOCKET)
                        errexit("accept failed: error number %d\n", WSAGetLastError());

                n = recv(connfd, BufferStore, BufferStoreLEN, 0);

                while (n > 0){
                        BufferStore[n] = '\0';
                        printf("%s\n", BufferStore);
                        printf("Input: ");
                        scanf("%s",str);
                        out = htonl(strlen(str));
                        Store = malloc(strlen(str));
                        for( q=0; q<strlen(str); q++)
                                Store[q] = str[q];
                        out = send(sockfd, Store, strlen(str), 0);
                        n = recv(connfd, BufferStore, BufferStoreLEN, 0);
                } 
                closesocket(sockfd);
                WSACleanup();
                free(str);
                free(BufferStore);
        }
}


One thing that's important to understand about stream sockets (SOCK_STREAM) is that they present you with a stream of bytes (hence the name :-)), without any "packet boundaries".

Specifically, if you send() 100 bytes of data from the client, the server may recv() it as

  • one recv() call returning 100 bytes
  • two recv()s of 50 bytes each
  • one recv() 90 bytes followed by 10 recv()s of 1 byte
  • ... etc ...

Your code appears to assume that what you send() on one end will be delivered in a single recv() call at the other end. For small chunks of data, that may work, but it's not something you can/should rely on.

In general, to do a command/response scenario like you're setting up, you need to have a way for the server to recognize "that's the end of the command, I should respond now". For example, if you're sending text strings, you can use a newline (\n) as the "end of command" marker.

The server would thus do multiple recv() calls (each one appending to a buffer) until it sees a \n (or an error), then send the response back; the client would do something similar when reading the response.


Your server is running inside an infinite loop, so to be able to send data that is input in the server application to the client application, you would have to read the user input in a different thread then send that to the user, as the infinite loop is currently blocking the current thread.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜