linux中每个进程默认情况下,最多可以打开1024个文件,最多有1024个文件描述符
文件描述符的特点:
1.非负整数
2.从最小可用的数字来分配
3.每个进程启动时默认打开0,1,2三个文件描述符
多路复用针对不止套接字fd,也针对普通的文件描述fd
sendto不阻塞
轮询不需要阻塞,一般写成这样很欠揍👀👀👀👀👀
- int main (void)
- {
- fd_set rset;
- int maxfd = -1;
-
- struct timeval tout;
-
- fd = socket ( ...);
- bind (fd, ...);
- listen (fd, ...);
-
- while (1) {
- maxfd = fd;
- FD_ZERO (&rset);
-
- FD_SET (fd, &rset);
- //依次把已经建立好连接fd加入到集合中,记录下来最大的文件描述符maxfd
- //...FIXME!!
- #if 0
- select (maxfd + 1, &rset, NULL, NULL, NULL);
- #else
- tout.tv_sec = 5;
- tout.tv_usec = 0;
- select (maxfd + 1, &rset, NULL, NULL, &tout);
- #endif
- if (FD_ISSET (fd, &rset)) {
- newfd = accept (fd, ....);
- }
- //依次判断已建立连接的客户端是否有数据
- //...FIXME!
-
- }
- return 0;
- }
- /*./client serv_ip serv_port */
- #include "net.h"
-
- void usage (char *s)
- {
- printf ("\n%s serv_ip serv_port", s);
- printf ("\n\t serv_ip: server ip address");
- printf ("\n\t serv_port: server port(>5000)\n\n");
- }
-
- int main (int argc, char **argv)
- {
- int fd = -1;
-
- int port = -1;
- struct sockaddr_in sin;
-
- if (argc != 3) {
- usage (argv[0]);
- exit (1);
- }
- /* 1. 创建socket fd */
- if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
- perror ("socket");
- exit (1);
- }
-
- port = atoi (argv[2]);
- if (port < 5000) {
- usage (argv[0]);
- exit (1);
- }
- /*2.连接服务器 */
-
- /*2.1 填充struct sockaddr_in结构体变量 */
- bzero (&sin, sizeof (sin));
-
- sin.sin_family = AF_INET;
- sin.sin_port = htons (port); //网络字节序的端口号
- #if 0
- sin.sin_addr.s_addr = inet_addr (SERV_IP_ADDR);
- #else
- if (inet_pton (AF_INET, argv[1], (void *) &sin.sin_addr) != 1) {
- perror ("inet_pton");
- exit (1);
- }
- #endif
-
- if (connect (fd, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
- perror ("connect");
- exit (1);
- }
-
- printf ("Client staring...OK!\n");
-
- int ret = -1;
- fd_set rset;
- int maxfd = -1;
- struct timeval tout;
- char buf[BUFSIZ];
-
- while (1) {
- FD_ZERO (&rset);
- FD_SET (0, &rset);
- FD_SET (fd, &rset);
- maxfd = fd;
-
- tout.tv_sec = 5;
- tout.tv_usec = 0;
-
- select (maxfd + 1, &rset, NULL, NULL, &tout);
- if (FD_ISSET (0, &rset)) { //标准键盘上有输入
- //读取键盘输入,发送到网络套接字fd
- bzero (buf, BUFSIZ);
- do {
- ret = read (0, buf, BUFSIZ - 1);
- } while (ret < 0 && EINTR == errno);
- if (ret < 0) {
- perror ("read");
- continue;
- }
- if (!ret)
- continue;
-
- if (write (fd, buf, strlen (buf)) < 0) {
- perror ("write() to socket");
- continue;
- }
-
- if (!strncasecmp (buf, QUIT_STR, strlen (QUIT_STR))) { //用户输入了quit字符
- printf ("Client is exiting!\n");
- break;
- }
- }
-
- if (FD_ISSET (fd, &rset)) { //服务器给发送过来了数据
- //读取套接字数据,处理
- bzero (buf, BUFSIZ);
- do {
- ret = read (fd, buf, BUFSIZ - 1);
- } while (ret < 0 && EINTR == errno);
- if (ret < 0) {
- perror ("read from socket");
- continue;
- }
- if (!ret)
- break; /* 服务器关闭 */
-
- //There is a BUG,FIXME!!
- printf ("server said: %s\n", buf);
- if (!strncasecmp (buf, QUIT_STR, strlen (QUIT_STR))) { //用户输入了quit字符
- printf ("Sender Client is exiting!\n");
- break;
- }
-
- }
- }
-
- /*4.关闭套接字 */
- close (fd);
- }
- #ifndef __MAKEU_NET_H__
- #define __MAKEU_NET_H__
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
/* See NOTES */ - #include
- #include
- #include
/* superset of previous */ -
- #include
- #include
- //#include
- #include
-
-
-
- #define SERV_PORT 5002
- #define SERV_IP_ADDR "192.168.7.246"
- #define BACKLOG 5
-
- #define QUIT_STR "quit"
-
- #endif
- #include
- #include
- #include "net.h"
-
- void cli_data_handle (void *arg);
-
- void sig_child_handle(int signo)
- {
- if(SIGCHLD == signo) {
- waitpid(-1, NULL, WNOHANG);
- }
- }
- int main (void)
- {
-
- int fd = -1;
- struct sockaddr_in sin;
-
- signal(SIGCHLD, sig_child_handle);
-
- /* 1. 创建socket fd */
- if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
- perror ("socket");
- exit (1);
- }
-
- /*优化4: 允许绑定地址快速重用 */
- int b_reuse = 1;
- setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));
-
-
- /*2. 绑定 */
- /*2.1 填充struct sockaddr_in结构体变量 */
- bzero (&sin, sizeof (sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons (SERV_PORT); //网络字节序的端口号
-
- /*优化1: 让服务器程序能绑定在任意的IP上 */
- #if 1
- sin.sin_addr.s_addr = htonl (INADDR_ANY);
- #else
- if (inet_pton (AF_INET, SERV_IP_ADDR, (void *) &sin.sin_addr) != 1) {
- perror ("inet_pton");
- exit (1);
- }
- #endif
- /*2.2 绑定 */
- if (bind (fd, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
- perror ("bind");
- exit (1);
- }
-
- /*3. 调用listen()把主动套接字变成被动套接字 */
- if (listen (fd, BACKLOG) < 0) {
- perror ("listen");
- exit (1);
- }
- printf ("Server starting....OK!\n");
- int newfd = -1;
- /*4. 阻塞等待客户端连接请求 */
-
- struct sockaddr_in cin;
- socklen_t addrlen = sizeof (cin);
- while(1) {
- pid_t pid = -1;
- if ((newfd = accept (fd, (struct sockaddr *) &cin, &addrlen)) < 0) {
- perror ("accept");
- break;
- }
- /*创建一个子进程用于处理已建立连接的客户的交互数据*/
- if((pid = fork()) < 0) {
- perror("fork");
- break;
- }
-
- if(0 == pid) { //子进程中
- close(fd);
- char ipv4_addr[16];
-
- if (!inet_ntop (AF_INET, (void *) &cin.sin_addr, ipv4_addr, sizeof (cin))) {
- perror ("inet_ntop");
- exit (1);
- }
-
- printf ("Clinet(%s:%d) is connected!\n", ipv4_addr, ntohs(cin.sin_port));
- cli_data_handle(&newfd);
- return 0;
-
- } else { //实际上此处 pid >0, 父进程中
- close(newfd);
- }
-
-
- }
-
-
- close (fd);
- return 0;
- }
-
- void cli_data_handle (void *arg)
- {
- int newfd = *(int *) arg;
-
- printf ("Child handling process: newfd =%d\n", newfd);
-
- //..和newfd进行数据读写
-
-
- int ret = -1;
- char buf[BUFSIZ];
- char resp_buf[BUFSIZ+10];
- while (1) {
- bzero (buf, BUFSIZ);
- do {
- ret = read (newfd, buf, BUFSIZ - 1);
- } while (ret < 0 && EINTR == errno);
- if (ret < 0) {
-
- perror ("read");
- exit (1);
- }
- if (!ret) { //对方已经关闭
- break;
- }
- printf ("Receive data: %s\n", buf);
-
- if (!strncasecmp (buf, QUIT_STR, strlen (QUIT_STR))) { //用户输入了quit字符
- printf ("Client(fd=%d) is exiting!\n", newfd);
- break;
- }
-
- bzero(resp_buf, BUFSIZ+10);
-
- strncpy(resp_buf, SERV_RESP_STR, strlen(SERV_RESP_STR));
- strcat(resp_buf, buf);
- do {
- ret = write(newfd, resp_buf, strlen(resp_buf));
- }while(ret < 0 && EINTR == errno);
-
- }
- close (newfd);
-
- }
- 1 #Makefile
- 2 #CROSS_COMPILE = arm-linux-gnu-
- 3 #CC = $(CROSS_COMPILE)gcc
- 4 CC = gcc
- 5 DEBUG = -g -o0 -Wall
- 6 CFLAGS += $(DEBUG)
- 7 PROGS = ${patsubst %.c, %, ${wildcard *.c}}
- 8 % : %.c
- 9 $(CC) $(CFLAGS) $< -o $@ -lpthread
- 10 all : $(PROGS)
- 11
这里出现了点问题老师的ubuntu和我的版本不同所以我还需要加两个头文件
具体可看报错合集2
然后有个错误有个宏不认识,man了半天,最后发现是自己定义的
#define SERV_RESP_STR "SERVER:"
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- typedef struct sockaddr Addr;
- typedef struct sockaddr_in Addr_in;
- typedef struct Node{
- int fd;
- struct Node *next;
- }Node;
-
- #define BACKLOG 5
-
- void Argment(int argc, char *argv[]);
- void NodeCreate(Node **p);
- void AcceptHandle(int sfd, Node **H);
- int ClientHandle(int fd);
-
- int main(int argc, char *argv[])
- {
- int ret, sfd, nfd = 0;
- Addr_in saddr;
- fd_set rfds;
- Node *H, *p = NULL;
-
- Argment(argc, argv);
-
- NodeCreate(&H);
-
- sfd = socket(AF_INET, SOCK_STREAM, 0);
- if(sfd < 0)
- {
- perror("socket");
- exit(0);
- }
-
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(atoi(argv[2]));
- saddr.sin_addr.s_addr = inet_addr(argv[1]);
-
- if(bind(sfd, (Addr *)&saddr, sizeof(Addr_in)))
- {
- perror("bind");
- exit(0);
- }
-
- if(listen(sfd, BACKLOG))
- {
- perror("listen");
- exit(0);
- }
-
- H->fd =sfd;
- while(1)
- {
- FD_ZERO(&rfds);
- p = H;
- nfd = 0;
- while(p != NULL)
- {
- if(p->fd > nfd)
- nfd = p->fd;
- FD_SET(p->fd, &rfds);
- p = p->next;
- }
- printf("nfd = %d run select...\n", nfd);
- ret =select(nfd+1, &rfds, NULL, NULL, NULL);
- if(!ret)
- continue;
- if(ret < 0)
- {
- perror("select");
- exit(0);
- }
- p = H;
- while(p->next != NULL)
- {
- if(FD_ISSET(p->fd, &rfds))
- {
- if(ClientHandle(p->fd) <= 0)
- {
- close(p->fd);
- Node *q = p->next;
- p->fd = q->fd;
- p->next = q->next;
- free(q);
- continue;
- }
- }
- p = p->next;
- }
- if(FD_ISSET(p->fd, &rfds))
- AcceptHandle(p->fd, &H);
- #if 1
- p = H;
- puts("");
- printf("Node:");
- while(p != NULL)
- {
- printf("%d ", p->fd);
- p = p->next;
- }
- #endif
- if(H->next == NULL)
- break;
- }
- close(sfd);
- free(H);
- return 0;
- }
-
- void Argment(int argc, char *argv[])//错误输出
- {
- if(argc != 3)
- {
- fprintf(stderr, "%s [addr] [port]\n", argv[0]);
- exit(0);
- }
- }
-
- void NodeCreate(Node **p)//创建节点
- {
- *p = malloc(sizeof(Node));
- if(p == NULL)
- {
- perror("malloc");
- exit(0);
- }
- bzero(*p, sizeof(Node));
- }
-
- void AcceptHandle(int sfd, Node **H)//Accept句柄
- {
- Node *p = NULL;
- Addr_in caddr;
- socklen_t caddr_len = sizeof(Addr_in);
- int cfd = accept(sfd, (Addr *)&caddr, &caddr_len);
- if(cfd < 0)
- {
- perror("accept");
- exit(0);
- }
- fprintf(stderr, "client %s:%d connect success.\n",
- inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
- NodeCreate(&p);
- p->fd = cfd;
- p->next = *H;
- *H = p;
- }
-
- int ClientHandle(int fd)//客户端句柄
- {
- int ret;
- char buf[1024] = {};
- ret = recv(fd, buf, 1024, 0);
- if(ret <= 0)
- return 0;
- printf("fd=%d buf = %s\n",fd, buf);
- if(buf[0] == '#')
- return 0;
- return ret;
- }