windows下基于select的 echo 客户端/服务器
程序代码:
#include <winsock2.h> #include <stdio.h> int Socket(int family, int type, int protocol) { int n; if ((n = socket(family, type, protocol)) < 0) { fputs("socket error", stderr); } return(n); } void Connect(int fd, const struct sockaddr *sa, int salen) { if (connect(fd, sa, salen) < 0) { fputs("connect error", stderr); } } void Send(int fd, const void *ptr, size_t nbytes, int flags) { if (send(fd, (const char*)ptr, nbytes, flags) != nbytes) { fputs("send error", stderr); } } void Bind(int fd, const struct sockaddr *sa, int salen) { if (bind(fd, sa, salen) < 0) { fputs("bind error", stderr); } } void Listen(int fd, int backlog) { if (listen(fd, 5) < 0) { fputs("listen error", stderr); } } int Accept(int fd, struct sockaddr *sa, int *salenptr) { int n; again: if ((n = accept(fd, sa, salenptr)) < 0) { if (GetLastError() == WSAECONNABORTED) { goto again; } else { fputs("accept error", stderr); } } return(n); } int Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int n; if ((n = select(nfds, readfds, writefds, exceptfds, timeout)) < 0) { int err = WSAGetLastError(); fputs("select error", stderr); } return(n); /* can return 0 on timeout */ } char* Fgets(char *ptr, int n, FILE *stream) { char* rptr; if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream)) { fputs("fgets error", stderr); } return (rptr); } void Fputs(const char *ptr, FILE *stream) { if (fputs(ptr, stream) == EOF) { fputs("fputs error", stderr); } } int writen(int fd, const void *vptr, size_t n) { size_t nleft; int nwritten; const char* ptr; ptr = (const char*)vptr; nleft = n; while (nleft > 0) { if ((nwritten = send(fd, ptr, nleft, 0)) <= 0) { if (nwritten < 0 && WSAGetLastError() == WSAEINTR) { nwritten = 0; /* and call write() again */ } else { return(-1); /* error */ } } nleft -= nwritten; ptr += nwritten; } return(n); } void Writen(int fd, void *ptr, size_t nbytes) { if (writen(fd, ptr, nbytes) != nbytes) { fputs("writen error", stderr); } } static int read_cnt; static char *read_ptr; static char read_buf[1024]; static int my_read(int fd, char *ptr) { if (read_cnt <= 0) { again: if ((read_cnt = recv(fd, read_buf, sizeof(read_buf), 0)) < 0) { if (WSAGetLastError() == WSAEINTR) { goto again; } return(-1); } else if (read_cnt == 0) { return(0); } read_ptr = read_buf; } read_cnt--; *ptr = *read_ptr++; return(1); } int readline(int fd, void *vptr, size_t maxlen) { int n, rc; char c, *ptr; ptr = (char*)vptr; for (n = 1; n < maxlen; n++) { if ((rc = my_read(fd, &c)) == 1) { *ptr++ = c; if (c == '\n') { break; /* newline is stored, like fgets() */ } } else if (rc == 0) { *ptr = 0; return(n - 1); /* EOF, n - 1 bytes were read */ } else { return(-1); /* error, errno set by read() */ } } *ptr = 0; /* null terminate like fgets() */ return(n); } int readlinebuf(void **vptrptr) { if (read_cnt) { *vptrptr = read_ptr; } return(read_cnt); } /* end readline */ int Readline(int fd, void *ptr, size_t maxlen) { int n; if ((n = readline(fd, ptr, maxlen)) < 0) { fputs("readline error", stderr); } return(n); } void Close(int fd) { if (closesocket(fd) == -1) { fputs("close error", stderr); } } void str_echo(int sockfd) { int n; char buf[1024]; again: while ((n = recv(sockfd, buf, 1024, 0)) > 0) { Writen(sockfd, buf, n); } if (n < 0 && WSAGetLastError() == WSAEINTR) { goto again; } else if (n < 0) { fputs("str_echo: read error", stderr); } } int main() { WSAData wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); int i, maxi, maxfd, listenfd, connfd, sockfd; int nready, client[FD_SETSIZE]; int n; fd_set rset, allset; char buf[1024]; int clilen; struct sockaddr_in cliaddr, servaddr; listenfd = Socket(AF_INET, SOCK_STREAM, 0); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(9877); servaddr.sin_addr.s_addr = INADDR_ANY; Bind(listenfd, (sockaddr*)&servaddr, sizeof(servaddr)); Listen(listenfd, 5); maxfd = listenfd; /* initialize */ maxi = -1; /* index into client[] array */ for (i = 0; i < FD_SETSIZE; i++) { client[i] = -1; /* -1 indicates available entry */ } FD_ZERO(&allset); FD_SET(listenfd, &allset); for (;;) { rset = allset; /* structure assignment */ nready = Select(maxfd+1, &rset, NULL, NULL, NULL); if (FD_ISSET(listenfd, &rset)) { /* new client connection */ clilen = sizeof(cliaddr); connfd = Accept(listenfd, (sockaddr*) &cliaddr, &clilen); for (i = 0; i < FD_SETSIZE; i++) { if (client[i] < 0) { client[i] = connfd; /* save descriptor */ break; } } if (i == FD_SETSIZE) { fputs("too many clients", stderr); } FD_SET(connfd, &allset); /* add new descriptor to set */ if (connfd > maxfd) { maxfd = connfd; /* for select */ } if (i > maxi) { maxi = i; /* max index in client[] array */ } if (--nready <= 0) { continue; /* no more readable descriptors */ } } for (i = 0; i <= maxi; i++) { /* check all clients for data */ if ((sockfd = client[i]) < 0) { continue; } if (FD_ISSET(sockfd, &rset)) { if ((n = recv(sockfd, buf, 1024, 0)) == 0) { /*4connection closed by client */ Close(sockfd); FD_CLR(sockfd, &allset); client[i] = -1; } else { Writen(sockfd, buf, n); } if (--nready <= 0) { break; /* no more readable descriptors */ } } } } }