C聊天。 Connect() 等待时间过长;服务器无法向客户端发送特定信息
C chat. Connect() waits for too long; server can't send particular info to a client
我在开发一个 Wi-Fi 多用户聊天程序。如果您能提供以下帮助,我将不胜感激。
- 由于路由器的 dhcp 特性,不清楚服务器机器每天会获得什么地址。客户端遍历所有可能主机的列表,从 192.168.1.1 开始。当它遇到非服务器设备时,它会等待一段随机的时间,最多一分钟。我怎样才能让它在一秒钟后停止等待?在阅读警报手册之前,我尝试使用 alarm() 停止它,所以这是浪费时间。
- 服务器函数
printUsers()
是唯一有时传递输出、有时不传递输出的函数。我很想有人解释为什么。
- 我想获得一些关于一般代码质量的反馈。我的意思是代码可读性和可维护性、程序设计、风格、错误处理等。
服务器代码
#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] == '[=10=]') { //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] = '[=10=]';
strcat(msgWelc, name);
sendMsg(fds[i].fd, msgWelc, SYS_MSG_LEN+NAME_LEN);
name[j] = '[=10=]';
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] = '[=10=]';
sendMsg(fd, names[j], NAME_LEN);
names[j][len] = '[=10=]';
}
}
}
//
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]!= '[=10=]'))
msg[len-1] = '[=10=]';
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] = '[=11=]';
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);
}
更新:
- 根据 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;
}
这里是第一个版本,使用非阻塞套接字和超时为 1 秒的 select
逐个尝试连接。我还更改了客户端中的其他一些内容以接收参数:
- 上面的主机号,程序将尝试从 192.168.1.1 连接到 192.168。1.upper_host 包括
- 可选
-d
冗长
客户端的完整程序,包括未修改的部分
#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);
void handleArgs(int argc, char *argv[], int * maxhost);
void sendErr(char *msg);
int main(int argc, char *argv[])
{
int maxhost; //search 192.168.1.1 .. 192.168.1.<MaxIP>
handleArgs(argc, argv, &maxhost);
//if (catchSignal(SIGALRM, doNoth) == -1)
// sendErr("Sigaction failed");
if (!findHost(maxhost)) {
puts("No hosts found");
exit(-1);
}
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)
{
if ((argc < 2) ||
(argc > 3) ||
(sscanf(argv[1], "%d", maxhost) != 1) ||
(*maxhost < 1) ||
((Debug = (argc == 3)) && strcmp(argv[2], "-d"))) {
fprintf(stderr, "Usage: %s max_host [-d]\n", *argv);
exit(-1);
}
}
//
void exit_closedConn()
{
puts("Server closed connection. Exiting...");
exit(1);
}
//
int do_connect(int host, 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.host */
sin.sin_port = htons(PORT);
sin.sin_family = AF_INET;
errno = 0;
int r = connect(sock, (struct sockaddr*) &sin, sizeof(sin));
if ((r < 0) && (errno != EINPROGRESS)) {
if (Debug)
printf("cannot connect to 192.168.1.%d\n", host);
close(sock);
return 0;
}
FD_SET(sock, fdset);
return sock;
}
int findHost(int maxhost)
{
int host;
puts("Searching for a server...");
for (host = 1; host <= maxhost; host += 1) {
fd_set rset;
FD_ZERO(&rset);
if ((MySock = do_connect(host, &rset)) != 0) {
fd_set wset = rset;
struct timeval timeout;
int r;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
r = select(MySock+1, &rset, &wset, NULL, &timeout);
if (r < 0)
sendErr("select");
else if (r) {
socklen_t len = sizeof(r);
if (!getsockopt(MySock, SOL_SOCKET, SO_ERROR, &r, &len) && !r) {
int flags;
if (Debug)
printf("connected to 192.168.1.%d\n", host);
/* put socket in blocking mode */
flags = fcntl(MySock, F_GETFL, 0);
if (fcntl(MySock, F_SETFL, flags ^ O_NONBLOCK) < 0)
sendErr("fcntl set non blocking");
alarm(OFF);
return SUCCESS;
}
}
if (Debug)
printf("cannot connect to 192.168.1.%d\n", host);
close(MySock);
}
}
return FAIL;
}
//
void sendErr(char *msg)
{
perror(msg);
exit(1);
}
但是,如果最大主机数很高,甚至限制为每台主机 1 秒,这可能会导致时间过长。
这里的第二个提议减少了对多个地址而不是一个地址进行连接尝试所需的时间,仍然使用非阻塞套接字和 select
超时为 1 秒。
客户端也修改为接收参数:
- 上面的主机号,程序将尝试从 192.168.1.1 连接到 192.168。1.upper_host 包括
- 可选的并行尝试次数,默认为 10
- 可选
-d
要冗长,要给出并行尝试的次数也必须给出
客户端的完整程序,包括未修改的部分:
#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; //search 192.168.1.1 .. 192.168.1.<MaxIP>
int npar = 10; //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);
if (Debug)
printf("cannot connect to 192.168.1.%d\n", host);
return 0;
}
if (sock > *highersock)
*highersock = sock;
FD_SET(sock, fdset);
return sock;
}
int findHost(int maxhost, int npar)
{
int host = 1;
puts("Searching for a server...");
while (host <= maxhost) {
fd_set rset;
int highersock = 0;
int i = 0, nsocks = 0;
int socks[npar]; /* socks under connection or 0 */
int hosts[npar]; /* the next host to check */
FD_ZERO(&rset);
/* establish socket list */
do {
int sock;
if ((sock = do_connect(host, &highersock, &rset)) != 0) {
socks[i] = sock;
hosts[i++] = host;
nsocks += 1;
}
host += 1;
} while ((i != npar) && (host <= maxhost));
/* check connects */
while (nsocks) {
fd_set rset2 = rset, wset2 = rset;
struct timeval timeout;
int r, j;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
r = select(highersock+1, &rset2, &wset2, NULL, &timeout);
if (r < 0)
sendErr("select");
if (r == 0) {
/* timeout, close all */
for (j = 0; j != i; ++j) {
if (socks[j])
close(socks[j]);
}
break;
}
for (j = 0; j != i; ++j) {
int sock = socks[j];
if (FD_ISSET(sock, &rset2) || FD_ISSET(sock, &wset2)) {
socklen_t len = sizeof(r);
socks[j] = 0;
FD_CLR(sock, &rset);
nsocks -= 1;
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);
}
else {
if (Debug)
printf("connected to 192.168.1.%d\n", hosts[j]);
/* close other sockets */
for (j = 0; j != i; ++j) {
if (socks[j] && (socks[j] != sock))
close(socks[j]);
}
MySock = sock;
/* 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);
}
您程序的其他部分未更改,请注意 chat
您发送了一个固定大小的数组,因此可能包含未初始化的字节。
我在开发一个 Wi-Fi 多用户聊天程序。如果您能提供以下帮助,我将不胜感激。
- 由于路由器的 dhcp 特性,不清楚服务器机器每天会获得什么地址。客户端遍历所有可能主机的列表,从 192.168.1.1 开始。当它遇到非服务器设备时,它会等待一段随机的时间,最多一分钟。我怎样才能让它在一秒钟后停止等待?在阅读警报手册之前,我尝试使用 alarm() 停止它,所以这是浪费时间。
- 服务器函数
printUsers()
是唯一有时传递输出、有时不传递输出的函数。我很想有人解释为什么。 - 我想获得一些关于一般代码质量的反馈。我的意思是代码可读性和可维护性、程序设计、风格、错误处理等。
服务器代码
#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] == '[=10=]') { //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] = '[=10=]';
strcat(msgWelc, name);
sendMsg(fds[i].fd, msgWelc, SYS_MSG_LEN+NAME_LEN);
name[j] = '[=10=]';
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] = '[=10=]';
sendMsg(fd, names[j], NAME_LEN);
names[j][len] = '[=10=]';
}
}
}
//
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]!= '[=10=]'))
msg[len-1] = '[=10=]';
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] = '[=11=]';
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);
}
更新:
- 根据 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;
}
这里是第一个版本,使用非阻塞套接字和超时为 1 秒的 select
逐个尝试连接。我还更改了客户端中的其他一些内容以接收参数:
- 上面的主机号,程序将尝试从 192.168.1.1 连接到 192.168。1.upper_host 包括
- 可选
-d
冗长
客户端的完整程序,包括未修改的部分
#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);
void handleArgs(int argc, char *argv[], int * maxhost);
void sendErr(char *msg);
int main(int argc, char *argv[])
{
int maxhost; //search 192.168.1.1 .. 192.168.1.<MaxIP>
handleArgs(argc, argv, &maxhost);
//if (catchSignal(SIGALRM, doNoth) == -1)
// sendErr("Sigaction failed");
if (!findHost(maxhost)) {
puts("No hosts found");
exit(-1);
}
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)
{
if ((argc < 2) ||
(argc > 3) ||
(sscanf(argv[1], "%d", maxhost) != 1) ||
(*maxhost < 1) ||
((Debug = (argc == 3)) && strcmp(argv[2], "-d"))) {
fprintf(stderr, "Usage: %s max_host [-d]\n", *argv);
exit(-1);
}
}
//
void exit_closedConn()
{
puts("Server closed connection. Exiting...");
exit(1);
}
//
int do_connect(int host, 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.host */
sin.sin_port = htons(PORT);
sin.sin_family = AF_INET;
errno = 0;
int r = connect(sock, (struct sockaddr*) &sin, sizeof(sin));
if ((r < 0) && (errno != EINPROGRESS)) {
if (Debug)
printf("cannot connect to 192.168.1.%d\n", host);
close(sock);
return 0;
}
FD_SET(sock, fdset);
return sock;
}
int findHost(int maxhost)
{
int host;
puts("Searching for a server...");
for (host = 1; host <= maxhost; host += 1) {
fd_set rset;
FD_ZERO(&rset);
if ((MySock = do_connect(host, &rset)) != 0) {
fd_set wset = rset;
struct timeval timeout;
int r;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
r = select(MySock+1, &rset, &wset, NULL, &timeout);
if (r < 0)
sendErr("select");
else if (r) {
socklen_t len = sizeof(r);
if (!getsockopt(MySock, SOL_SOCKET, SO_ERROR, &r, &len) && !r) {
int flags;
if (Debug)
printf("connected to 192.168.1.%d\n", host);
/* put socket in blocking mode */
flags = fcntl(MySock, F_GETFL, 0);
if (fcntl(MySock, F_SETFL, flags ^ O_NONBLOCK) < 0)
sendErr("fcntl set non blocking");
alarm(OFF);
return SUCCESS;
}
}
if (Debug)
printf("cannot connect to 192.168.1.%d\n", host);
close(MySock);
}
}
return FAIL;
}
//
void sendErr(char *msg)
{
perror(msg);
exit(1);
}
但是,如果最大主机数很高,甚至限制为每台主机 1 秒,这可能会导致时间过长。
这里的第二个提议减少了对多个地址而不是一个地址进行连接尝试所需的时间,仍然使用非阻塞套接字和 select
超时为 1 秒。
客户端也修改为接收参数:
- 上面的主机号,程序将尝试从 192.168.1.1 连接到 192.168。1.upper_host 包括
- 可选的并行尝试次数,默认为 10
- 可选
-d
要冗长,要给出并行尝试的次数也必须给出
客户端的完整程序,包括未修改的部分:
#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; //search 192.168.1.1 .. 192.168.1.<MaxIP>
int npar = 10; //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);
if (Debug)
printf("cannot connect to 192.168.1.%d\n", host);
return 0;
}
if (sock > *highersock)
*highersock = sock;
FD_SET(sock, fdset);
return sock;
}
int findHost(int maxhost, int npar)
{
int host = 1;
puts("Searching for a server...");
while (host <= maxhost) {
fd_set rset;
int highersock = 0;
int i = 0, nsocks = 0;
int socks[npar]; /* socks under connection or 0 */
int hosts[npar]; /* the next host to check */
FD_ZERO(&rset);
/* establish socket list */
do {
int sock;
if ((sock = do_connect(host, &highersock, &rset)) != 0) {
socks[i] = sock;
hosts[i++] = host;
nsocks += 1;
}
host += 1;
} while ((i != npar) && (host <= maxhost));
/* check connects */
while (nsocks) {
fd_set rset2 = rset, wset2 = rset;
struct timeval timeout;
int r, j;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
r = select(highersock+1, &rset2, &wset2, NULL, &timeout);
if (r < 0)
sendErr("select");
if (r == 0) {
/* timeout, close all */
for (j = 0; j != i; ++j) {
if (socks[j])
close(socks[j]);
}
break;
}
for (j = 0; j != i; ++j) {
int sock = socks[j];
if (FD_ISSET(sock, &rset2) || FD_ISSET(sock, &wset2)) {
socklen_t len = sizeof(r);
socks[j] = 0;
FD_CLR(sock, &rset);
nsocks -= 1;
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);
}
else {
if (Debug)
printf("connected to 192.168.1.%d\n", hosts[j]);
/* close other sockets */
for (j = 0; j != i; ++j) {
if (socks[j] && (socks[j] != sock))
close(socks[j]);
}
MySock = sock;
/* 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);
}
您程序的其他部分未更改,请注意 chat
您发送了一个固定大小的数组,因此可能包含未初始化的字节。