服务器端:

#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>#define SIN_PORT 9999
#define BUFLEN 256void str_echo(int fd);void sig_child(int signo)
{pid_t pid;int stat;while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {printf("pid %d terminated\n", pid);}}size_t readn(int fd, void *ptr, size_t n)
{char *p = ptr;size_t nleft = n;size_t nread;while (nleft > 0) {if ((nread = read(fd, p, nleft)) < 0) {if (errno == EINTR) nread = 0;else return -1;} else if (nread == 0) break;nleft -= nread;p += nread;}return n - nleft;
}size_t readline(int fd, void *ptr, size_t maxsize)
{char *p = ptr;size_t rc, n;char c;for (n = 1; n < maxsize; n++) {
again:if ((rc = read(fd, &c, 1)) == 1) {*p++ = c;if (c == '\n') break;} else if (rc == 0) {if (n == 1) return 0;else break;} else {if (errno == EINTR) goto again;return -1;}}*p = 0;return n;
}size_t writen(int fd, void *ptr, size_t n)
{char *p = ptr;size_t nleft = n,  nwriten;while (nleft > 0) {if ((nwriten = write(fd, p, nleft)) <= 0) {if (errno == EINTR) nwriten = 0;else return -1;}p += nwriten;nleft -= nwriten;}return n;
}void str_echo(int fd)
{char recvline[BUFLEN];int n;for (;;) {if ((n = readline(fd, recvline, BUFLEN)) == 0) return;printf("received buf=%s", recvline);writen(fd, recvline, n);}
}int main(int argc, char **argv)
{int listenfd, connfd, sockfd;int maxfd, i, maxi, n;int nready, client[FD_SETSIZE];pid_t child;struct sockaddr_in servaddr, clientaddr;char buf[BUFLEN];time_t ticks;fd_set rset, allset;int len;listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd < 0) {printf("socket error :%s\n", strerror(errno));        return -1;}servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SIN_PORT);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);signal(SIGCHLD, sig_child);if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {printf("bind error:%s\n", strerror(errno));close(listenfd);return -1;}if (listen(listenfd, 3) < 0) {printf("listen error:%s\n", strerror(errno));close(listenfd);return -1;}maxfd = listenfd;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)) {len = sizeof(int);connfd = accept(listenfd, (struct sockaddr*)&clientaddr, &len);for (i = 0; i < FD_SETSIZE; i++) {if (client[i] < 0) {client[i] = connfd;break;}}if (i == FD_SETSIZE) {printf("too many client\n");return;}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 = readline(sockfd, buf, BUFLEN)) == 0) {close(sockfd);FD_CLR(sockfd, &allset);client[i] = -1;} else {writen(sockfd, buf, n);}}if (--nready <= 0) break;}}return 0;
}

用一个client数组记录连接后的socket,同时将这个socket加入到描述字符集中。在监听到有连接请求后,遍历可用的字符集,因为readline是阻塞的,会出现拒绝式攻击。

可行的解决方法 有如下 三种:

(1)使用非阻塞I/O模型

(2)让每个客户由单独的控制线程提供服务(创建子进程或线程来为每个客户提供服务)

(3)对I/O设置 超时

客户端:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>#define SIN_PORT 9999
#define BUF_LEN 256
#define max(a, b) ((a) > (b) ? (a) : (b))size_t readline(int fd, void *ptr, int maxsize)
{char *p = ptr;char c;int rc;int n;for (n = 1; n < maxsize; n++) {again:if ((rc = read(fd, &c, 1)) == 1) {*p++ = c;if (c == '\n') break; } else if (rc == 0) {if (n == 1) return 0;else break;}else {if (errno == EINTR) goto again;else return -1;}}*p = 0;return n;
}size_t readn(int fd, void *ptr, size_t n)
{char *p = ptr;int nleft = n;int nread;while (nleft > 0) {if ((nread = read(fd, p, nleft)) < 0) {if (errno == EINTR) nread = 0;else return -1;} else if (nread == 0) break;nleft -= nread;p += nread;}return n - nleft;
}size_t writen(int fd, void *ptr, size_t n)
{size_t nwriten;size_t nleft = n;char *p = ptr;while (nleft > 0) {if ((nwriten = write(fd, p, nleft)) <= 0) {if (errno == EINTR) nwriten = 0;else return -1;}nleft -= nwriten;p += nwriten;}return n;
}void str_cli(FILE *file, int fd)
{char recvline[BUF_LEN], sendline[BUF_LEN];int maxfdp1;fd_set fdset;int ret;int stdineof = 0;FD_ZERO(&fdset);for(;;) {if (stdineof == 0)FD_SET(fileno(file), &fdset);FD_SET(fd, &fdset);maxfdp1 = max(fileno(file), fd) + 1;ret = select(maxfdp1, &fdset, NULL, NULL, NULL);   if (ret <= 0) {continue;}//printf("ret=%d\n", ret);if (FD_ISSET(fd, &fdset)) {if (readline(fd, recvline, BUF_LEN) == 0) {if (stdineof == 1)return;else {printf("readline error:%s\n", strerror(errno));return;}}fputs(recvline, stdout);} if (FD_ISSET(fileno(file), &fdset)) {memset(sendline, 0x00, sizeof(sendline));if (fgets(sendline, BUF_LEN, file) == NULL) {//printf("fgets error:%s\n", strerror(errno));stdineof = 1;shutdown(fd, SHUT_WR);FD_CLR(fileno(file), &fdset);continue;}//printf("len=%d\n", strlen(sendline));writen(fd, sendline, strlen(sendline));}   }
}int main(int argc, char** argv)
{struct sockaddr_in serveraddr;int sockfd;#ifndef ONLINE_JUDGE//freopen("6.4Client.c", "r", stdin);
#endifsockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) {printf("socket error:%s\n", strerror(errno));return -1;}   serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(SIN_PORT);if (inet_pton(AF_INET, argv[1], &serveraddr.sin_addr) != 1) {printf("inet_pton error:%s\n", strerror(errno));close(sockfd);return -1;}if (connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) {printf("connect error:%s\n", strerror(errno));close(sockfd);return -1;}str_cli(stdin, sockfd);exit(0);}

网络编程学习笔记(TCP回射服务器程序修订版)相关推荐

  1. Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍

    转载:http://blog.csdn.net/michael_kong_nju/article/details/43457393 写在开头: 在上一节中我们学习了一些基础的用来支持网络编程的API, ...

  2. UNIX网络编程——使用线程的TCP回射服务器程序

    同一进程内的所有线程除了共享全局变量外还共享: (1)进程指令: (2)大多数数据: (3)  打开的文件(即描述符): (4)信号处理函数和信号处置: (5)当前工作目录: (6)用户ID和组ID. ...

  3. 网络编程学习笔记(TCP套接口选项)

    其套接口级别为IPPROTO_TCP TCP_KEEPALIVE: 指定TCP开始发送保持存活探测分节前以秒为单位的连接空闲时间.此选项在SO_KEEPALIVE套接口选项打开时才有效 TCP_MAX ...

  4. UNIX网络编程学习笔记(代码超详细解析)(持续更新)

    1. 其他函数准备 1. TCP 回射服务器程序: str_echo 函数 #include "unp.h"void str_echo(int sockfd) {ssize_t n ...

  5. 15Java网络编程学习笔记

    Java网络编程学习笔记 文章目录 1 网络基础 1.1 网络通信 1.2 网络 1.3 IP地址 1.5 域名 1.6 端口号 1.7 网络通信协议 1.8 TCP协议 1.9 UDP协议 2 In ...

  6. java 网络编程学习笔记

    java 网络编程学习笔记 C/S模式:客户端和服务器 客户端创建流程 1 1.建立Socket端点 2 3 Socket s = new Socket(绑定地址, 绑定端口); 2.确认源数据方式和 ...

  7. [Linux网络编程学习笔记]索引

    一.Linux基本知识 [学习笔记]Linux平台的文件I/O操作 [学习笔记]Linux平台的文件,目录及操作 [Linux学习笔记]标准输入输出 [Linux学习笔记]进程概念及控制 [Linux ...

  8. 网络编程学习笔记(非阻塞accept)

    修改TCP回射客户程序,在跟服务器建立连接后发送一个RST.这种情况可以如下模拟: 一旦建立连接,设置SO_LINGER选项,把l_onoff标志置为1,l_linger时间置为0.在关闭连接时,TC ...

  9. 编程开发:Linux网络编程学习笔记

    非常全面.通俗易懂.值得借鉴的Linux网络编程学习笔记.关键字:linux linux编程 网络编程 linux网络编程 下载地址:点我下载 特别说明:本资源收集于网络,版权归原作者及版权商所有,仅 ...

最新文章

  1. 【数据结构-查找】3.散列表详解
  2. step2 . day7 C语言阶段小的项目总结
  3. python中的wx_配置 Python的wxWidgets可视开发环境 | 学步园
  4. 全栈工程师已经过时?
  5. 使用go的ssh包快速打造一个本地命令行ssh客户端
  6. Xcode 创建自定义模板
  7. 20145302张薇《Java程序设计》第十周学习总结
  8. OSPFv3中LSA详解(九)——Prefix三元组详解
  9. 服务器装系统不识别硬盘分区,安装系统无法识别分区解决方法
  10. 阿里云搭建 ftp 服务器
  11. 中华人民共和国国家标准和行业标准代号
  12. A股股票交易如何计算
  13. 创建windows虚拟机详细教程
  14. MATLAB频数表-tabulate/hist
  15. 【JZOJ4598】准备食物
  16. 位运算符:按位取反(~)、位与()、位或(|)、位异或(^);左移运算符(<<)、右移运算符(>>)
  17. Vuepress2版本打包报错:TypeError: Invalid value used as weak map key
  18. 电商平台关键词、商品详情API、品牌维护、价格监控、竞价比价
  19. 苏泊尔公布财报一季度承压,营收大幅下跌后龙头之位还稳吗?
  20. 计算机电源可调电阻,PC电源改可调电源

热门文章

  1. python为什么这么火 知乎-没想到 Google 排名第一的编程语言,为什么会这么火?...
  2. python程序设计 清华大学出版社 pdf下载-清华大学出版社-图书详情-《Python程序设计》...
  3. python这个软件学会能做什么工作-学会Python真的有高收入?盯,请查收这份入坑指南...
  4. 与python相关的考研专业-给考研人:掌握这项技能,让你每天的学习高效又充实...
  5. python起步输入-Python编程起步——输入与输出
  6. 学完了python能做什么-学会Python后都能做什么?网友们的回答简直不要太厉害
  7. python爬虫代码1000行-简单用14行代码写一个Python代理IP的爬虫
  8. python中读取文件内容-Python从文件中读取数据(2)
  9. python软件怎么用-Python如何创建应用程序
  10. python软件界面-python软件界面介绍(python软件介绍)