回射服务器没有做出错处理:
#include
#include
#include
#include
#include
#include
#include
#include
#define SERV_PORT 5000
#define MAXLINE 64
void str_echo(int fd);
void sig_chld(int signo);
int main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
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, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listenfd, 5);
// 获取子进程的结束信号并用sig_chld做处理, signal()函数在多线程显示是没有定义的
// 一般是用sigaction来替换, 我这图方便
if (signal(SIGCHLD, sig_chld) == SIG_ERR){
fprintf(stderr, "can't catch SIGCHLD \n");
exit(0);
}
for ( ; ; ){
clilen = sizeof(cliaddr);
if ( (connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) < 0){
if (errno == EINTR) // accept 在阻塞的时候被signal打断会返回EINTR错误存于errno
continue; // back to for()
else{
fprintf(stderr, "accept error\n");
exit(0);
}
}
if ((childpid = fork()) == 0){ // child
close(listenfd); // close listening socket
str_echo(connfd);// process the request
exit(0);
}
close(connfd); // parent closes connected socket
}
return 0;
}
void str_echo(int sockfd)
{
int n;
char buf[MAXLINE];
again:
while ( (n = read(sockfd, buf, MAXLINE)))
write(sockfd, buf, n);
if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
printf("str_echo: read error");
}
void sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);// printf() isn't suitable for use here
return;
}
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 1024
#define SERV_PORT 5000
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; // 再次执行write()
else
return -1; // error
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
int main(int argc, char **argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE];
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);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct 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, (struct sockaddr *) &cliaddr, &clilen);
for (i = 0; i < FD_SETSIZE; ++i) {
if (client[i] < 0) {
client[i] = connfd; // save descriptor
break;
}
}
if (i == FD_SETSIZE) {
fprintf(stderr, "too many clients");
exit(1);
}
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[i] 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 = read(sockfd, buf, MAXLINE)) == 0) {
// connection 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
}
}
}
exit(0);
}
#include // for OPEN_MAX
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 1024
#define SERV_PORT 5000
#define OPEN_MAX 1024
#define INFTIM -1
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; // 再次执行write()
else
return -1; // error
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
int main(int argc, char **argv)
{
int i, maxi, listenfd, connfd, sockfd;
int nready;
ssize_t n;
char buf[MAXLINE];
socklen_t clilen;
struct pollfd client[OPEN_MAX];
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listenfd, 5);
client[0].fd = listenfd;
client[0].events = POLLRDNORM;
for (i = 0; i < OPEN_MAX; ++i)
client[i].fd = -1; // indicates available entry
maxi = 0; // max index into client[] array
for ( ; ; ) {
nready = poll(client, maxi + 1, INFTIM);
if (client[0].revents & POLLRDNORM) { // new client connection
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
for (i = 1; i < OPEN_MAX; ++i) {
if (client[i].fd < 0) {
client[i].fd = connfd; // save descriptor
break;
}
}
if (OPEN_MAX == i) {
printf("too many clients");
exit(1);
}
client[i].events = POLLRDNORM;
if (i > maxi)
maxi = i; // max index in client[] array
if (--nready <= 0)
continue; // no more readable descriptors
}
for (i = 1; i <= maxi; ++i) { // check all clients for data
if ( (sockfd = client[i].fd) < 0)
continue;
if (client[i].revents & (POLLRDNORM | POLLERR)) {
if ( (n = read(sockfd, buf, MAXLINE)) < 0) {
if (errno == ECONNRESET) {
// connection reset by client
close(sockfd);
client[i].fd = -1;
} else if (0 == n) {
// connection closed by client
close(sockfd);
client[i].fd = -1;
} else
writen(sockfd, buf, n);
if (--nready <= 0)
break; // no more readable descriptors
}
}
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#define SERV_PORT 5000
#define MAXLINE 1024
void str_cli(FILE *fp, int sockfd);
// 这个readline代码很低效,因为它是一个字符一个字符的读取的
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; // newline is stored
} else if (rc == 0){
*ptr = 0;
return (n - 1); // EOF, n - 1 bytes
} else {
if (errno == EINTR)
goto again;
return -1; /// error, errno set by read()
}
}
*ptr = 0;
return n;
}
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2){
fprintf(stderr, "usage: tcpcli " );
return 1;
}
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, (struct sockaddr *) &servaddr, sizeof(servaddr));
str_cli(stdin, sockfd); // do it all
exit(0);
}
void str_cli(FILE *fp, int sockfd)
{
char sendline[MAXLINE], recvline[MAXLINE];
while (fgets(sendline, MAXLINE, fp) != NULL){
write(sockfd, sendline, strlen(sendline));
if (readline(sockfd, recvline, MAXLINE) == 0)
printf("str_cli:server terminated prematurely");
fputs(recvline, stdout);
}
}
void str_cli(FILE *fp, int sockfd)
{
int maxfdp1;
fd_set rset;
char sendline[MAXLINE], recvline[MAXLINE];
FD_ZERO(&rset);
for ( ; ; ) {
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 (readline(sockfd, recvline, MAXLINE) == 0)
printf("str_cli: server terminated prematurely");
fputs(recvline, stdout);
}
if (FD_ISSET(fileno(fp), &rset)) { // input is readable
if (NULL == fgets(sendline, MAXLINE, fp))
return ; // all done
writen(sockfd, sendline, strlen(sendline));
}
}
}