C聊天。 Connect()等待太长时间;服务器无法将特定信息发送到客户端

问题描述 投票:0回答:1

我正在研究Wi-Fi多用户聊天程序。在以下方面,我将不胜感激。

  1. 由于路由器的dhcp特性,目前尚不清楚服务器每天将获得什么地址。客户端浏览所有可能的主机列表,从192.168.1.1开始。当遇到非服务器设备时,它将等待随机的时间,最多一分钟。如何让它在一秒钟后停止等待?在尝试阅读警报手册之前,我尝试使用alarm()停止它,因此浪费时间。
  2. 服务器功能printUsers()是唯一其输出有时被传递而有时不被传递的函数。我希望有人解释原因。
  3. 我想对一般代码质量有一些反馈。我的意思是诸如代码的可读性和可维护性,程序设计,样式,错误处理等。

服务器代码

#include <arpa/inet.h>
#include <ctype.h>
#include <ifaddrs.h>
#include <netdb.h>       //adds symbolic network constants
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#define BYE           0
#define ERROR         -1
#define HOST_SIZE     4
#define MAX_CONN      11
#define MSG_LEN       255
#define NAME_LEN      30
#define SYS_MSG_LEN  18

int debug;            //command-line argument
int mySock;           //sustains value from assignment till the end
typedef struct pollfd pollfd; 

void addName2msg(char name[], char msg[], char msgOut[]);
void addUser(char name[], int i, char msg[], pollfd *fds, int fdsInd);
void findMyIP(char myIP[]);
void handleArgs(int argc, char *argv[]);
void handleLeaver(int i, char names[][NAME_LEN], pollfd *fds, int*fdI);
void handleNewClient(pollfd *fds, int *fdsInd);
void printUsers(char names[][NAME_LEN], int i, int fd);
void sendAll(int i, char msgOut[], pollfd *fds, int fdsInd);
void sendErr(char *msg);
void sendMsg(int fd, char msg[], int len);
void startHost(char myIP[]);


void workLoop()
{
    static pollfd fds[MAX_CONN];
    int status, fdsInd = 0; 
    static char names[MAX_CONN+1][NAME_LEN];
    char msg[MSG_LEN], msgOut[MSG_LEN+NAME_LEN]; 

    fds[fdsInd].fd = mySock;
    fds[fdsInd++].events = POLLIN;

    while(1) {
        if (debug)
            puts("Waiting for an event to happen...");
        if (poll(fds, fdsInd, -1) == -1)
            sendErr("poll() failed");
        if (debug)
            puts("An event happened");
        for (int i = 0; i < fdsInd; i++) {
            if ((fds[i].fd == mySock) && (fds[i].revents & POLLIN)) {
                handleNewClient(fds, &fdsInd);
            } else if (fds[i].revents & POLLIN) { //handle message
                status = recv(fds[i].fd, msg, MSG_LEN, 0);
                if (debug)
                    printf("Recieved msg from %s, socket %d\n", 
                                          names[i], fds[i].fd);

                if ((status == BYE) || (status == ERROR)) {
                    printf("Status is %d\n", status == BYE? BYE: ERROR);
                    handleLeaver(i, names, fds, &fdsInd);
                    continue;
                }
                if (*names[i] == '\0')  {   //no name? Save msg as name
                    addUser(names[i], i, msg, fds, fdsInd);
                    printUsers(names, i, fds[i].fd);
                    continue;
                }
                addName2msg(names[i], msg, msgOut);
                sendAll(i, msgOut, fds, fdsInd);
            }
        }
    }
}


int main(int argc, char *argv[])
{
    char myIP[INET_ADDRSTRLEN];

    handleArgs(argc, argv);
    findMyIP(myIP);              
    startHost(myIP);
    workLoop();

    return 0;
}
//
void addName2msg(char name[], char msg[], char msgOut[]) {
    int len;
    strncpy(msgOut, name, NAME_LEN );
    len = strlen(msgOut);
    msgOut[len] = ':';
    msgOut[len+1] = ' ';
    strcat(msgOut, msg);
}
//
void addUser(char name[], int i, char msg[], pollfd *fds, int fdsInd)
{
    int j;
    char msgWelc[SYS_MSG_LEN + NAME_LEN] = "Welcome to chat, ";
    char msgJoin[SYS_MSG_LEN] = " joined the chat\n";

    for (j = 0; j < NAME_LEN-3; j++) {
        if (msg[j] == '\n' || isspace(msg[j]))
            break;
        name[j] = msg[j];
    }
    name[j] = '\n';
    name[j+1] = '\0';
    strcat(msgWelc, name);
    sendMsg(fds[i].fd, msgWelc, SYS_MSG_LEN+NAME_LEN);
    name[j] = '\0';
    strncpy(msgWelc, name, NAME_LEN);
    strcat(msgWelc, msgJoin);
    sendAll(i, msgWelc, fds, fdsInd);
}
//
void findMyIP(char myIP[])
{
    struct ifaddrs *addrs;
    struct sockaddr_in *pAddr;

    getifaddrs(&addrs);
    for (; addrs != NULL; addrs = addrs->ifa_next) {
        pAddr = (struct  sockaddr_in *) addrs->ifa_addr;
        if (strstr(inet_ntoa(pAddr->sin_addr), "192.168.1") != NULL)
            strncpy(myIP, inet_ntoa(pAddr->sin_addr), INET_ADDRSTRLEN);
    }
    freeifaddrs(addrs);
    if (debug)
        printf("Local IP is %s\n", myIP);
}
//
void handleArgs(int argc, char *argv[])
{
    if (argc > 2) {
        puts("error: one arg max");
        exit(1);
    }
    if ((argc == 2) && (strcmp("-d", argv[argc-1]) != 0)) {
        puts("error: Call with -d for debugging");
        exit(1);
    } else if (argc == 2)
        debug = 1;
}
//
void handleLeaver(
     int i, char names[][NAME_LEN], pollfd *fds, int *fdsInd)
{
    int lastElem = *fdsInd - 1;
    char trash[MSG_LEN];
    char msgLeft[SYS_MSG_LEN] = " left the chat\n";

    //notify all users
    strncpy(trash, names[i], strlen(names[i])+1);   
    strcat(trash, msgLeft);
    sendAll(i, trash, fds, *fdsInd);

    if (debug) {
        printf("Had: fds0:%d fds1:%d fds2:%d; fdsInd: %d\n", 
                    fds[0].fd, fds[1].fd, fds[2].fd, *fdsInd);
        printf("\tNames1: %s, Names2: %s\n", names[1], names[2]);
    }
    recv(fds[i].fd, trash, MSG_LEN, 0);  //receive garbage

    if (lastElem == i) { 
        fds[i].fd = 0;
        fds[i].events = 0;
        (*fdsInd)--;
        names[i][0] = 0;
    } else {           
        fds[i].fd = fds[lastElem].fd;
        fds[i].events = fds[lastElem].events;
        strncpy(names[i], names[lastElem], NAME_LEN);
        fds[lastElem].fd = 0;
        fds[lastElem].events = 0;   
        (*fdsInd)--;
        names[lastElem][0] = 0;
    }
    if (debug) {
        printf("Removed user\n");
        printf("Have: fds0:%d fds1:%d fds2:%d; fdsInd: %d\n", 
                    fds[0].fd, fds[1].fd, fds[2].fd, *fdsInd);
        printf("\tNames1: %s, Names2: %s\n", names[1], names[2]);
    }
}
//
void handleNewClient(pollfd *fds, int *fdsInd)
{
    struct sockaddr clientInfo;
    socklen_t addrSz;
    int newFD; 
    char nameReq[SYS_MSG_LEN] = "Enter your name: ";

    addrSz = sizeof(clientInfo);
    newFD = accept(mySock, &clientInfo, &addrSz); 
    if (*fdsInd > MAX_CONN) {   //kill extra users
        close(newFD);
        return;
    }
    fds[*fdsInd].fd = newFD;
    fds[(*fdsInd)++].events = POLLIN;
    if (debug)
        puts("Accepted a client");
    sendMsg(newFD, nameReq, SYS_MSG_LEN);
}
//
void printUsers(char names[][NAME_LEN], int i, int fd)
{
    int len;
    char msgStart[SYS_MSG_LEN] = "Online Users:\n";
    sendMsg(fd, msgStart, SYS_MSG_LEN);
    if (debug)
        printf("Online users printed for %s, %d\n", names[i], fd);

    for (int j = 0; j < MAX_CONN; j++) {
        if ((names[j][0] != 0) && (strcmp(names[j], names[i]) != 0)) {
            len = strlen(names[j]);
            names[j][len] = '\n';
            names[j][len+1] = '\0';
            sendMsg(fd, names[j], NAME_LEN);
            names[j][len] = '\0';
        }
    }
}
//
void sendAll(int i, char msgOut[], pollfd *fds, int fdsInd)
{
    pollfd *author = &fds[i];

    for (int j = 0; j < fdsInd; j++) {
        if (fds[j].fd == author->fd)  
            continue;
        if  (fds[j].fd == mySock)    
            continue;
        sendMsg(fds[j].fd, msgOut, MSG_LEN);
    }
}
//
void sendErr(char *msg)
{
    perror(msg);
    exit(1);
}
//
void sendMsg(int fd, char msg[], int len)
{
    int sent = 0;

    if ((len == MSG_LEN) && (msg[len-1]!= '\0'))
        msg[len-1] = '\0';
    if ((len == MSG_LEN) && (msg[len-2]!= '\n'))
        msg[len-2] = '\n';

    while (sent < len) {
        sent = send(fd, msg, len, 0);
        if (sent == -1)
            sendErr("Sending message failed");
        else if (sent == len)
            return;
    }
}
//
void startHost(char myIP[])
{
    struct addrinfo hints, *servinfo;
    int yes = 1; 
    char port[] = "39071";

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;     // any IPv*
    hints.ai_socktype = SOCK_STREAM;

    if (getaddrinfo(myIP, port, &hints, &servinfo) != 0)
        sendErr("Getaddinfo() failed");

    if ((mySock = socket(servinfo->ai_family, 
                  servinfo->ai_socktype, servinfo->ai_protocol)) == -1)
        sendErr("Socket() failed");

    if (-1 == setsockopt(
              mySock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)))
        sendErr("setsockopt() failed");

    if (bind(mySock, servinfo->ai_addr, servinfo->ai_addrlen) == -1)
        sendErr("Bind() failed");

    if (listen(mySock, MAX_CONN) == -1)
        sendErr("listen() failed");

    if (debug) {
        printf("Host socket is %d\n", mySock);
        printf("Listening to port %s...\n", port);
    }
}

客户代码

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netdb.h>       //adds symbolic network constants
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#define FDS_NUM            2
#define HOST_SIZE          4
#define MSG_LEN            255
#define MAX_CONN          11

enum { ERROR = -1, OFF = 0, SERV_DOWN = 0 , FAIL = 0, SUCCESS = 1 };

int debug;            //command-line argument
int mySock;           //received in prepareNet() and kept till the end

//int catchSignal(int sig, void (*handler)(int));
void chat();
//void doNoth(int sig) { sig = sig; return; }
void exit_closedConn();
int findHost(struct addrinfo *servinfo[]);
void handleArgs(int argc, char *argv[]);
void prepareNet(struct addrinfo *servinfo[]);
void sendErr(char *msg);

int main(int argc, char *argv[])
{
    struct addrinfo *servinfo[MAX_CONN];

    handleArgs(argc, argv);
    prepareNet(servinfo);
    //if (catchSignal(SIGALRM, doNoth) == -1)
    //        sendErr("Sigaction failed");
    if (!findHost(servinfo))
        sendErr("No hosts found");
    chat();

    return 0;
}
//
int catchSignal(int sig, void (*handler)(int))
{
    struct sigaction new;

    new.sa_handler = handler;
    sigemptyset(&new.sa_mask);
    new.sa_flags = 0;

    return sigaction(sig, &new, NULL);
}
//
void chat()
{
    struct pollfd pds[FDS_NUM];  
    int status;
    char msgIn[MSG_LEN];
    char usrMsg[MSG_LEN];
    pds[0].fd = 0;  //stdin
    pds[1].fd = mySock;
    pds[0].events = pds[1].events = POLLIN;
    while (1) {
        if (poll(pds, FDS_NUM, -1) == -1)
            sendErr("Poll failed");

        if (pds[0].revents & POLLIN) {
            fgets(usrMsg, MSG_LEN, stdin);
            if (send(pds[1].fd, usrMsg, MSG_LEN, 0) == -1)
                sendErr("Sent failed");
        } else if (pds[1].revents & POLLIN) {
            if ((status = recv(pds[1].fd, msgIn, MSG_LEN, 0)) == ERROR)
                sendErr("recv failed");
            else if (status == SERV_DOWN)
                exit_closedConn();
            printf("%s", msgIn);
            fflush(stdout);
        }
    }
}
//
void handleArgs(int argc, char *argv[])
{
    if (argc > 2) 
        sendErr("1 argument max");
    if ((argc == 2) && (strcmp("-d", argv[argc-1]) != 0)) 
        sendErr("input -d for debugging");
    else if (argc == 2)
        debug = 1;
}
//
void exit_closedConn()
{
    puts("Server closed connection. Exiting...");
    exit(1);
}
//
int findHost(struct addrinfo *servinfo[])
{
    puts("Searching for a server...");
    for (int i = 1; i < MAX_CONN; i++)   {
        if (debug)
            printf("Trying for 192.168.1.%d...\n", i);
        //alarm(1);
        if (connect(mySock, servinfo[i]->ai_addr, 
                    servinfo[i]->ai_addrlen) != -1)  {
            alarm(OFF);
            printf("Connected to 192.168.1.%d\n",i);
            return SUCCESS;
        }
    }
    return FAIL;
}
//
void prepareNet(struct addrinfo *servinfo[])
{
    struct addrinfo hints[MAX_CONN];
    char port[] = "39071";

    for (int i = 0; i < MAX_CONN; i++) {
        char host[HOST_SIZE];
        char ip[INET_ADDRSTRLEN] = "192.168.1.";

        memset(&hints[i], 0, sizeof(hints[i]));
        hints[i].ai_family = AF_UNSPEC;     // any IPv*
        hints[i].ai_socktype = SOCK_STREAM;
        sprintf(host, "%d", i);
        host[3] = '\0';
        strncat(ip, host, HOST_SIZE-1);

        if (getaddrinfo(ip, port, &hints[i], &servinfo[i]) != 0)
            sendErr("Getaddinfo() failed");
    }
    if ((mySock = socket(servinfo[0]->ai_family, 
            servinfo[0]->ai_socktype, servinfo[0]->ai_protocol)) == -1)
        sendErr("Socket() failed");
    if (debug)
        printf("Trying port %s using socket %d\n", port, mySock);
}
//
void sendErr(char *msg)
{
    perror(msg);
    exit(1);
}

更新:

  1. 按照Cix和bruno的建议,我能够解决第一个问题。详细信息如下:
    • 程序创建一个套接字并尝试连接
    • 设置第二个警报后
    • alarm()的信号处理程序是一个伪函数
    • 如果没有建立连接,程序将关闭套接字

问题是这种方法有多好?

int findHost(struct addrinfo *servinfo[])
{
    puts("Searching for a server...");
    for (int i = 1; i < MAX_CONN; i++)   {
        if ((mySock = socket(servinfo[0]->ai_family, 
                servinfo[0]->ai_socktype, servinfo[0]->ai_protocol)) == -1)
            sendErr("Socket() failed");
        if (debug) 
            printf("Trying for 192.168.1.%d...\n", i);
        alarm(1);
        if (connect(mySock, servinfo[i]->ai_addr, 
                    servinfo[i]->ai_addrlen) != -1)  {
            alarm(OFF);
            printf("Connected to 192.168.1.%d\n",i);
            //remove non-blocking
            return SUCCESS;
        }
        //sleep(1);
        close(mySock);
    }
    return FAIL;
}
c server client connect send
1个回答
0
投票

[使用无阻塞插槽限制connect的时间,并使用1秒的超时限制select的时间,这可能不是正确的方法。

首先,您确定您的服务器将需要少于第二秒的时间来回答,并且因为您要继续使用新地址,因此无法使用以前的套接字,并且对我来说尚不清楚,可以安全地在关闭套接字之前关闭套接字连接尝试结束。

因此,我建议您尝试使用无阻塞套接字和select 超时与多个地址并行连接。

在我的提案中,当连接完成后,我当然不会尝试与其他尚未尝试的地址进行连接,但我会等待正在进行的尝试完成。

客户端被修改为接收参数:

  • 上层主机号,程序将尝试从192.168.1.1到192.168.1.upper_host进行连接
  • [可选,并行尝试的次数,默认为10
  • 可选地,-d冗长,也必须给出并行尝试的次数

这里是完整程序,我只修改了与连接相关的部分,请注意,在chat中您发送了固定大小的数组,因此可能包含未初始化的字节。

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netdb.h>       //adds symbolic network constants
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define FDS_NUM            2
#define HOST_SIZE          4
#define MSG_LEN            255

#define PORT 39071

enum { ERROR = -1, OFF = 0, SERV_DOWN = 0 , FAIL = 0, SUCCESS = 1 };

int Debug;       //command-line argument
int MySock;      //the successfuly connected socket

//int catchSignal(int sig, void (*handler)(int));
void chat();
//void doNoth(int sig) { sig = sig; return; }
void exit_closedConn();
int findHost(int maxhost, int npar);
void handleArgs(int argc, char *argv[], int * maxhost, int * npar);
void sendErr(char *msg);

int main(int argc, char *argv[])
{
  int maxhost = 10;  //search 192.168.1.1 .. 192.168.1.<MaxIP>
  int npar;        //number of // connections

  handleArgs(argc, argv, &maxhost, &npar);

    //if (catchSignal(SIGALRM, doNoth) == -1)
    //        sendErr("Sigaction failed");
  if (!findHost(maxhost, npar))
    sendErr("No hosts found");
  else
    puts("host found");

  chat();

  return 0;
}
//
int catchSignal(int sig, void (*handler)(int))
{
    struct sigaction new;

    new.sa_handler = handler;
    sigemptyset(&new.sa_mask);
    new.sa_flags = 0;

    return sigaction(sig, &new, NULL);
}
//
void chat()
{
    struct pollfd pds[FDS_NUM];  
    int status;
    char msgIn[MSG_LEN];
    char usrMsg[MSG_LEN];
    pds[0].fd = 0;  //stdin
    pds[1].fd = MySock;
    pds[0].events = pds[1].events = POLLIN;
    while (1) {
        if (poll(pds, FDS_NUM, -1) == -1)
            sendErr("Poll failed");

        if (pds[0].revents & POLLIN) {
            fgets(usrMsg, MSG_LEN, stdin);
            if (send(pds[1].fd, usrMsg, MSG_LEN, 0) == -1)
                sendErr("Sent failed");
        } else if (pds[1].revents & POLLIN) {
            if ((status = recv(pds[1].fd, msgIn, MSG_LEN, 0)) == ERROR)
                sendErr("recv failed");
            else if (status == SERV_DOWN)
                exit_closedConn();
            printf("%s", msgIn);
            fflush(stdout);
        }
    }
}

//

void handleArgs(int argc, char *argv[], int * maxhost, int * npar)
{
  if ((argc < 2) || 
      (argc > 4) ||
      (sscanf(argv[1], "%d", maxhost) != 1) ||
      (*maxhost < 1) ||
      ((argc >= 3) && ((sscanf(argv[2], "%d", npar) != 1) || (*npar < 1))) ||
      ((Debug = (argc == 4)) && strcmp(argv[3], "-d"))) {
    fprintf(stderr, "Usage: %s max_host [n_par [-d]] (default n_par is 10)\n", *argv);
    exit(-1);
  }
}

//

void exit_closedConn()
{
  puts("Server closed connection. Exiting...");
  exit(1);
}

//

int do_connect(int host, int * highersock, fd_set * fdset)
{
  if (Debug)
    printf("Trying for 192.168.1.%d...\n", host);

  int sock = socket(AF_INET, SOCK_STREAM, 0);

  if (fcntl(sock, F_SETFL,O_NONBLOCK) != 0)
    sendErr("fcntl nonblock");

  struct sockaddr_in sin = { 0 };

  sin.sin_addr.s_addr = htonl(0xC0a80100 + host); /* 192.168.1. */
  sin.sin_port = htons(PORT);
  sin.sin_family = AF_INET; /////AF_UNSPEC;     // any IPv*

  errno = 0;

  int r = connect(sock, (struct sockaddr*) &sin, sizeof(sin));

  if ((r < 0) && (errno != EINPROGRESS)) {
    close(sock);
    return 0;
  }

  if (sock > *highersock)
    *highersock = sock;

  FD_SET(sock, fdset);
  return sock;
}

int findHost(int maxhost, int npar)
{
  int socks[npar];    /* socks under connection or 0 */
  int hosts[npar];    /* the next host to check */
  int highersock = 0; /* for select */
  fd_set fdset;
  int i = 0, nsocks = 0, host = 1;

  memset(socks, 0, sizeof(int)*npar);
  FD_ZERO(&fdset);

  puts("Searching for a server...");

  /* set the initial list */
  do {
    int sock = do_connect(host, &highersock, &fdset);

    if (sock != 0) {
      socks[i] = sock;
      hosts[i++] = host;
    }
  } while ((++host <= maxhost) && (i != npar));

  nsocks = i;

  while (nsocks) {
    fd_set rset2 = fdset;
    fd_set wset2 = fdset;

    if (select(highersock+1, &rset2, &wset2, NULL, NULL) < 0)
      sendErr("select");

    for (int j = 0; j != i; ++j) {
      int sock = socks[j];

      if (sock &&
          (FD_ISSET(sock, &rset2) || FD_ISSET(sock, &wset2))) {
        int r;
        socklen_t len = sizeof(r);

        FD_CLR(sock, &rset2);
        FD_CLR(sock, &wset2);
        FD_CLR(sock, &fdset);
        nsocks -= 1;
        socks[j] = 0;

        if (sock == highersock) {
          /* must be recomputed */
          highersock = socks[0];

          for (int k = 1; k < i; ++k) {
            if (socks[k] > highersock)
              highersock = socks[k];
          }
        }

        if ((getsockopt(sock, SOL_SOCKET, SO_ERROR, &r, &len) < 0) || r) {
          if (Debug)
            printf("cannot connect to 192.168.1.%d\n", hosts[j]);
          close(sock);

          if (!MySock) {
            /* replace it with an other */
            while (host <= maxhost) {
              if ((sock = do_connect(host, &highersock, &fdset)) != 0) {
                socks[j] = sock;
                hosts[j] = host++;
                nsocks += 1;
                break;
              }
              host += 1;
            }
          }
        }
        else {
          if (Debug)
            printf("connected to 192.168.1.%d\n", hosts[j]);
          MySock = sock;
          /* may be you want to return, without waiting other attempts finish */
        }
      }
    }
  }

  if (MySock) {
    /* put socket in blocking mode */
    int flags = fcntl(MySock, F_GETFL, 0);

    if (fcntl(MySock, F_SETFL, flags ^ O_NONBLOCK) < 0)
      sendErr("fcntl set non blocking");

    alarm(OFF);
    return SUCCESS;
  }

  return FAIL;
}

//
void sendErr(char *msg)
{
    perror(msg);
    exit(1);
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.