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 */
}
}
}
}
}







