0

我正在编写简单的 TCP 服务器,但发现了一些问题。也许你能帮我一点忙。所以,我先写了一个回显服务器(测试与计算机客户端的连接)。它工作正常,但现在我需要稍微改变一下。服务器应在连接时向客户端发送 char[100],并每隔 X 秒/分钟向每个客户端发送相同的 char[]。

我尝试了很多更改,但应用程序只会崩溃。在这段代码中评论了我的一些“错误”。

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

/* BufferLength is 100 bytes */
#define BufferLength 100
/* Server port */
#define SERVPORT 6000



int main(){

/* Variable and structure definitions. */

int sd, wyslij, sd2, rc, length = sizeof(int);
int totalcnt = 0, on = 1;
char temp;
char buffer[BufferLength];
struct sockaddr_in serveraddr;
struct sockaddr_in their_addr;

fd_set read_fd;
struct timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;

char datadata[100] = "This is a test string from server lol!!! ";

/* Get a socket descriptor */
if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
    perror("Server-socket() error");
    /* exit */
    exit (-1);
}else
    printf("Server-socket() is OK\n");

/* Allow socket descriptor to be reusable */

if((rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0){
    perror("Server-setsockopt() error");
    close(sd);
    exit (-1);
}else
    printf("Server-setsockopt() is OK\n");


    /* bind to an address */
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

printf("Using %s, listening at %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT);


if((rc = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0){
    perror("Server-bind() error");
    /* Close the socket descriptor */
    close(sd);
    /* and just exit */
    exit(-1);
}else
    printf("Server-bind() is OK\n");

/* queue up to 10 clients  */

if((rc = listen(sd, 10)) < 0){
    perror("Server-listen() error");
    close(sd);
    exit (-1);
}else
    printf("Server-Ready for client connection...\n");

/* accept() the incoming connection request. */
int sin_size = sizeof(struct sockaddr_in);

if((sd2 = accept(sd, (struct sockaddr *)&their_addr, &sin_size)) < 0){
    perror("Server-accept() error");
    close(sd);
    exit (-1);
}else
    printf("Server-accept() is OK\n");

/*client IP*/

printf("Server-new socket, sd2 is OK...\n");
printf("Got connection from the client: %s\n", inet_ntoa(their_addr.sin_addr));

/* Wait for up to 15 seconds on */
/* select() for data to be read. */

FD_ZERO(&read_fd);
FD_SET(sd2, &read_fd);
rc = select(sd2+1, &read_fd, NULL, NULL, &timeout);


/* rc = write(sd2, datadata, sizeof(datadata)); */
if((rc == 1) && (FD_ISSET(sd2, &read_fd))){

/* rc = write(sd2, datadata, sizeof(datadata)); */

/* Read data from the client. */
totalcnt = 0;

    while(totalcnt < BufferLength){
    /* read() from client */

        rc = read(sd2, &buffer[totalcnt], (BufferLength - totalcnt));

        if(rc < 0){
            perror("Server-read() error");
            close(sd);
            close(sd2);
            exit (-1);
        }else if (rc == 0){
            printf("Client program has issued a close()\n");
            close(sd);
            close(sd2);
            exit(-1);
        }
        else{
            totalcnt += rc;
            printf("Server-read() is OK\n");
        }
    }
}else if (rc < 0){
    perror("Server-select() error");
    close(sd);
    close(sd2);
    exit(-1);
}
/* rc == 0 */
else{
    printf("Server-select() timed out.\n");
    close(sd);
    close(sd2);
    exit(-1);
}


/* Shows the data */

printf("Received data from the client: %s\n", buffer);

/* write() some bytes of string, */
/* back to the client. */

printf("Server-Echoing back to client...\n");
rc = write(sd2, datadata, sizeof(datadata));

if(rc != totalcnt){
    perror("Server-write() error");
    /* Get the error number. */
    rc = getsockopt(sd2, SOL_SOCKET, SO_ERROR, &temp, &length);

    if(rc == 0){
        /* Print out the asynchronously */
        /* received error. */
        errno = temp;
        perror("SO_ERROR was: ");
    }else
        printf("Server-write() is OK\n");
        close(sd);
        close(sd2);
        exit(-1);
    }

/* Close the connection to the client and */
/* close the server listening socket. */

close(sd2);
close(sd);
exit(0);

return 0;
}

非常感谢小伙伴们!

4

2 回答 2

2

You may want to check out D.J. Bernstein's tcpserver (see http://cr.yp.to/ucspi-tcp/tcpserver.html). Basically, you can simply run your C program under tcpserver, and tcpserver will handle everything as far as setting up the sockets, listing for incoming connections on whatever port you are using, etc. When an incoming connection arrives on the port that you specify, tcpserver will spawn an instance of your program and pipe incoming info from the client to your program's STDIN, and pipe outgoing info from your program's STDOUT back to the client. This way, you can concentrate on your program's core logic (and simply read/write to stdout/stdin), and let tcpserver handle all of the heavy lifting as far as the sockets, etc.

于 2013-07-29T13:35:43.283 回答
1

Well, I ran your program against a simple TCP client code and did not see any crash. So, you probably should add gdb info to that. Also, in the program, I don't see where your programs wakes up periodically (you do have a comment) and sends data to the client. You should also consider adding the client fd to the list of read fd set and have one common select() call. If the select() returns a read-event on the listener, then that is a new connection and you should call accept. If the select() returns a read-event on a child fd, then you have some data to read adn you should call recv()/read().

于 2013-07-30T02:17:12.390 回答