服务器端 tcpserv.c
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#define LISTENQ 1024
#define MAXLINE 4096
#define SERV_PORT 9877
#define SA struct sockaddr
int main(int argc, char* argv[])
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE];
//pid_t childpid;
ssize_t n;
fd_set rset, allset;
char buf[MAXLINE];
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
maxfd = listenfd;
maxi = -1;
for(i = 0; i < FD_SETSIZE; i++)
{
client[i] = -1;
}
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
for(; ;)
{
rset = allset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if(FD_ISSET(listenfd, &rset)){
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (SA*)&cliaddr, &clilen);
for(i = 0; i < FD_SETSIZE; i++)
{
if(client[i] < 0)
{
client[i] = connfd; //save discriptor
break;
}
}
if(i == FD_SETSIZE)
{
err_quit("too many clients");
}
FD_SET(connfd, &allset);
if(connfd > maxfd)
{
maxfd = connfd;
}
if(i > maxi)
{
maxi = i;
}
if(--nready <= 0)
{
continue;
}
}
for(i = 0; i <= maxi; i++)
{
if((sockfd = client[i]) < 0)
{
continue;
}
if(FD_ISSET(sockfd, &rset)){
if((n = read(sockfd, buf, MAXLINE)) == 0)
{
close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
}
else
{
writen(sockfd, buf, n);
}
if(--nready)
{
break;
}
}
}
}
//for(; ; )
//{
// clilen = sizeof(cliaddr);
// connfd = accept(listenfd, (SA*)&cliaddr, &clilen);
// if((childpid = fork()) == 0)
// {
// close(listenfd);
// str_echo(connfd);
// exit(0);
// }
// close(connfd);
//}
exit(0);
}
客户端 tcpcli.c
- #include <unistd.h>
- #include <stdio.h>
- #include <sys/socket.h>
- #include <string.h>
- #include <arpa/inet.h>
- #include <stdlib.h>
- #define SERV_PORT 9877
- #define SA struct sockaddr
- int main(int argc, char* argv[])
- {
- int sockfd;
- struct sockaddr_in servaddr;
- if(argc != 2)
- {
- err_quit("usage: tcpcli <IPaddress>");
- }
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(SERV_PORT);
- inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
- connect(sockfd, (SA*)&servaddr, sizeof(servaddr));
- str_cli(stdin,sockfd);
- exit(0);
- }
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/socket.h>
-
- #define MAXLINE 4096
-
- #undef max
- #define max(x,y) ((x)>(y)?(x):(y))
-
- void str_cli(FILE* fp, int sockfd);
- #include "str_cli.h"
-
- void str_cli(FILE* fp, int sockfd)
- {
- int maxfdp1, stdineof;
- fd_set rset;
- char buf[MAXLINE];
- int n;
-
- stdineof = 0;
- FD_ZERO(&rset);
-
- for( ; ;)
- {
- if(stdineof == 0)
- FD_SET(fileno(fp), &rset);
- FD_SET(sockfd, &rset);
- maxfdp1 = max(fileno(fp), sockfd) + 1;
-
- select(maxfdp1, &rset, NULL, NULL, NULL);
- if(FD_ISSET(sockfd, &rset)) //socket is readable
- {
- if((n = read(sockfd, buf, MAXLINE)) == 0)
- {
- if(stdineof == 1)
- {
- return;
- }
- else
- {
- err_quit("str_cli: server terminated prematurely");
- }
- }
- write(fileno(stdout), buf, n);
- }
-
- if(FD_ISSET(fileno(fp), &rset)) //input is readable
- {
- if((n = read(fileno(fp), buf, MAXLINE)) == 0)
- {
- stdineof = 1;
- shutdown(sockfd, SHUT_WR);
- FD_CLR(fileno(fp), &rset);
- continue;
- }
- writen(sockfd, buf, n);
- }
- }
- }
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #define MAXLINE 4096
- void str_echo(int sockfd);
- #include "str_echo.h"
- void str_echo(int sockfd)
- {
- ssize_t n;
- char buf[MAXLINE];
- again:
- while((n = read(sockfd, buf, MAXLINE)) > 0)
- {
- writen(sockfd, buf, n);
- }
- if(n < 0 && errno == EINTR)
- {
- goto again;
- }
- else if(n < 0)
- {
- err_sys("str_echo: read error");
- }
- }
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- ssize_t writen(int fd, const void*vptr, size_t n);
- #include "writen.h"
- ssize_t writen(int fd, const void*vptr, size_t n)
- {
- size_t nleft;
- ssize_t nwritten;
- const char *ptr;
- ptr = vptr;
- nleft = n;
- while(nleft > 0)
- {
- if((nwritten = write(fd, ptr, nleft)) <= 0)
- {
- if(nwritten < 0 && errno == EINTR)
- {
- nwritten = 0;
- }
- else
- {
- return(-1);
- }
- }
- nleft -= nwritten;
- ptr += nwritten;
- }
- return(n);
- }
readline.h
- #include <unistd.h>
- #include <stdlib.h>
- #include <errno.h>
- ssize_t readline(int fd, void* vptr, size_t maxlen);
- #include "readline.h"
- ssize_t readline(int fd, void* vptr, size_t maxlen)
- {
- ssize_t n, rc;
- char c, *ptr;
- ptr = vptr;
- for(n = 1; n < maxlen; n++)
- {
- again:
- if((rc = read(fd, &c, 1)) == 1)
- {
- *ptr++ = c;
- if(c == '\n')
- {
- break;
- }
- }
- else if(rc == 0)
- {
- *ptr = 0;
- return (n-1);
- }
- else
- {
- if(errno == EINTR)
- {
- goto again;
- }
- return(-1);
- }
- }
- *ptr = 0;
- return(n);
- }
- #ifndef ERROR_H
- #define ERROR_H
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
- #include <unistd.h>
- #include <syslog.h>
- #include <errno.h>
- #include "constant.h"
- static void err_doit(int, int, const char *, va_list);
- void err_ret(const char *fmt, ...);
- void err_sys(const char *fmt, ...);
- void err_dump(const char *fmt, ...);
- void err_msg(const char *fmt, ...);
- void err_quit(const char *fmt, ...);
- #endif
- #include "error.h"
- int daemon_proc; /* set nonzero by daemon_init() */
- static void err_doit(int, int, const char *, va_list);
- /* Nonfatal error related to system call
- * * Print message and return */
- void err_ret(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- err_doit(1, LOG_INFO, fmt, ap);
- va_end(ap);
- return;
- }
- /* Fatal error related to system call
- * * Print message and terminate */
- void err_sys(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- err_doit(1, LOG_ERR, fmt, ap);
- va_end(ap);
- exit(1);
- }
- /* Fatal error related to system call
- * * Print message, dump core, and terminate */
- void err_dump(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- err_doit(1, LOG_ERR, fmt, ap);
- va_end(ap);
- abort(); /* dump core and terminate */
- exit(1); /* shouldn't get here */
- }
- /* Fatal error unrelated to system call
- * * Print message and terminate */
- void err_quit(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- err_doit(0, LOG_ERR, fmt, ap);
- va_end(ap);
- exit(1);
- }
- /* Print message and return to caller
- * * Caller specifies "errnoflag" and "level" */
- static void err_doit(int errnoflag, int level, const char *fmt, va_list ap)
- {
- int errno_save,n;
- char buf[MAXLINE + 1];
- errno_save = errno; /* value caller might want printed */
- #ifdef HAVE_VSNPRINTF
- vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
- #else
- vsprintf(buf, fmt, ap); /* not safe */
- #endif
- n = strlen(buf);
- if (errnoflag)
- snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
- strcat(buf, "\n");
- if (daemon_proc) {
- syslog(level, buf);
- }
- else
- {
- fflush(stdout); /* in case stdout and stderr are the same */
- fputs(buf, stderr);
- fflush(stderr);
- }
- return;
- }
- #ifndef Constant_H
- #define Constant_H
- #ifndef MAXLINE
- #define MAXLINE 4096
- #endif
- #ifndef LISTENQ
- #define LISTENQ 1024
- #endif
- #ifndef BUFFSIZE
- #define BUFFSIZE 8092
- #endif
- #endif
makefile
- bins = tcpserv tcpcli
- objs = tcpserv.o tcpcli.o str_echo.o str_cli.o writen.o readline.o error.o
- srcs = tcpserv.c tcpcli.c str_echo.c str_echo.h str_cli.c str_cli.h \
- writen.c writen.h readline.c readline.h error.c error.h
- $(bins):$(objs)
- gcc -o tcpserv tcpserv.o str_echo.o writen.o readline.o error.o
- gcc -o tcpcli tcpcli.o str_cli.o writen.o readline.o error.o
- $(objs):$(srcs)
- gcc -c tcpserv.c
- gcc -c tcpcli.c
- gcc -c str_echo.c str_echo.h error.h
- gcc -c str_cli.c str_cli.h
- gcc -c writen.c writen.h
- gcc -c readline.c readline.h
- gcc -c error.c error.h
- clean:
- rm -rf $(bins) *.o *.h.gch