原始碼完全註釋:socket select
原始碼地址:https://github.com/shaojunlv/socket-select
客戶端程式碼:
/**************************************************************************/
/* Generic client example is used with connection-oriented server designs */
/**************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_PORT 12345 //埠號
main (int argc, char *argv[])
{
int len, rc;
int sockfd;
char send_buf[80];
char recv_buf[80];
struct sockaddr_in addr;
/*************************************************/
/* Create an AF_INET stream socket */
/*************************************************/
sockfd = socket(AF_INET, SOCK_STREAM, 0); //建立套接字
if (sockfd < 0)
{
perror("socket");
exit(-1);
}
/*************************************************/
/* Initialize the socket address structure */
/*************************************************/
memset(&addr, 0, sizeof(addr)); //分配記憶體
addr.sin_family = AF_INET; //ipv4
addr.sin_addr.s_addr = htonl(INADDR_ANY); //接收客戶端的型別
addr.sin_port = htons(SERVER_PORT); //使用的埠
/*************************************************/
/* Connect to the server */
/*************************************************/
rc = connect(sockfd, //將套接字與地址建立連結
(struct sockaddr *)&addr,
sizeof(struct sockaddr_in));
if (rc < 0)
{
perror("connect");
close(sockfd);
exit(-1);
}
printf("Connect completed.socketfd is %d .rc is %d \n",sockfd,rc);
/*************************************************/
/* Enter data buffer that is to be sent */
/*************************************************/
printf("Enter message to be sent:\n");
gets(send_buf);
/*************************************************/
/* Send data buffer to the worker job */
/*************************************************/
len = send(sockfd, send_buf, strlen(send_buf) + 1, 0); //向埠傳送
if (len != strlen(send_buf) + 1)
{
perror("send");
close(sockfd);
exit(-1);
}
printf("%d bytes sent\n", len);
/*************************************************/
/* Receive data buffer from the worker job */
/*************************************************/
len = recv(sockfd, recv_buf, sizeof(recv_buf), 0); //從埠接收
if (len != strlen(send_buf) + 1)
{
perror("recv");
close(sockfd);
exit(-1);
}
printf("%d bytes received\n", len);
/*************************************************/
/* Close down the socket */
/*************************************************/
close(sockfd);
}
伺服器端程式碼:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#define SERVER_PORT 12345
#define TRUE 1
#define FALSE 0
main (int argc, char *argv[])
{
int i, len, rc, on = 1;
int listen_sd, max_sd, new_sd;
int desc_ready, end_server = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in addr;
struct timeval timeout;
fd_set master_set, working_set;
/*************************************************************/
/* Create an AF_INET stream socket to receive incoming */
/* connections on */
/*************************************************************/
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sd < 0)
{
perror("socket() failed");
exit(-1);
}
/*************************************************************/
/* Allow socket descriptor to be reuseable */
/*************************************************************/
rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < 0)
{
perror("setsockopt() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Set socket to be non-blocking. All of the sockets for */
/* the incoming connections will also be non-blocking since */
/* they will inherit that state from the listening socket. */
/*************************************************************/
rc = ioctl(listen_sd, FIONBIO, (char *)&on);
if (rc < 0)
{
perror("ioctl() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Bind the socket */
/*************************************************************/
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
rc = bind(listen_sd,
(struct sockaddr *)&addr, sizeof(addr));
if (rc < 0)
{
perror("bind() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Set the listen back log */
/*************************************************************/
rc = listen(listen_sd, 32);
if (rc < 0)
{
perror("listen() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Initialize the master fd_set */
/*************************************************************/
FD_ZERO(&master_set);
max_sd = listen_sd;
FD_SET(listen_sd, &master_set);
/*************************************************************/
/* Initialize the timeval struct to 3 minutes. If no */
/* activity after 3 minutes this program will end. */
/*************************************************************/
timeout.tv_sec = 3 * 60;
timeout.tv_usec = 0;
/*************************************************************/
/* Loop waiting for incoming connects or for incoming data */
/* on any of the connected sockets. */
/*************************************************************/
do
{
/**********************************************************/
/* Copy the master fd_set over to the working fd_set. */
/**********************************************************/
memcpy(&working_set, &master_set, sizeof(master_set));
/**********************************************************/
/* Call select() and wait 5 minutes for it to complete. */
/**********************************************************/
printf("listen_sd is %d ",listen_sd);
printf("Waiting on select()...\n");
rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout);
/**********************************************************/
/* Check to see if the select call failed. */
/**********************************************************/
if (rc < 0)
{
perror(" select() failed");
break;
}
/**********************************************************/
/* Check to see if the 5 minute time out expired. */
/**********************************************************/
if (rc == 0)
{
printf(" select() timed out. End program.\n");
break;
}
/**********************************************************/
/* One or more descriptors are readable. Need to */
/* determine which ones they are. */
/**********************************************************/
desc_ready = rc;
for (i=0; i <= max_sd && desc_ready > 0; ++i)
{
/*******************************************************/
/* Check to see if this descriptor is ready */
/*******************************************************/
if (FD_ISSET(i, &working_set))
{
/****************************************************/
/* A descriptor was found that was readable - one */
/* less has to be looked for. This is being done */
/* so that we can stop looking at the working set */
/* once we have found all of the descriptors that */
/* were ready. */
/****************************************************/
desc_ready -= 1;
/****************************************************/
/* Check to see if this is the listening socket */
/****************************************************/
if (i == listen_sd)
{
printf(" Listening socket is readable\n");
/*************************************************/
/* Accept all incoming connections that are */
/* queued up on the listening socket before we */
/* loop back and call select again. */
/*************************************************/
do
{
/**********************************************/
/* Accept each incoming connection. If */
/* accept fails with EWOULDBLOCK, then we */
/* have accepted all of them. Any other */
/* failure on accept will cause us to end the */
/* server. */
/**********************************************/
new_sd = accept(listen_sd, NULL, NULL);
if (new_sd < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" accept() failed");
end_server = TRUE;
}
break;
}
/**********************************************/
/* Add the new incoming connection to the */
/* master read set */
/**********************************************/
printf(" New incoming connection - %d\n", new_sd);
FD_SET(new_sd, &master_set);
if (new_sd > max_sd)
max_sd = new_sd;
/**********************************************/
/* Loop back up and accept another incoming */
/* connection */
/**********************************************/
} while (new_sd != -1);
}
/****************************************************/
/* This is not the listening socket, therefore an */
/* existing connection must be readable */
/****************************************************/
else
{
printf(" Descriptor %d is readable\n", i);
close_conn = FALSE;
/*************************************************/
/* Receive all incoming data on this socket */
/* before we loop back and call select again. */
/*************************************************/
do
{
/**********************************************/
/* Receive data on this connection until the */
/* recv fails with EWOULDBLOCK. If any other */
/* failure occurs, we will close the */
/* connection. */
/**********************************************/
rc = recv(i, buffer, sizeof(buffer), 0);
if (rc < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" recv() failed");
close_conn = TRUE;
}
break;
}
/**********************************************/
/* Check to see if the connection has been */
/* closed by the client */
/**********************************************/
if (rc == 0)
{
printf(" Connection closed\n");
close_conn = TRUE;
break;
}
/**********************************************/
/* Data was recevied */
/**********************************************/
len = rc;
printf(" %d bytes received\n", len);
/**********************************************/
/* Echo the data back to the client */
/**********************************************/
rc = send(i, buffer, len, 0);
if (rc < 0)
{
perror(" send() failed");
close_conn = TRUE;
break;
}
} while (TRUE);
/*************************************************/
/* If the close_conn flag was turned on, we need */
/* to clean up this active connection. This */
/* clean up process includes removing the */
/* descriptor from the master set and */
/* determining the new maximum descriptor value */
/* based on the bits that are still turned on in */
/* the master set. */
/*************************************************/
if (close_conn)
{
close(i);
FD_CLR(i, &master_set);
if (i == max_sd)
{
while (FD_ISSET(max_sd, &master_set) == FALSE)
max_sd -= 1;
}
}
} /* End of existing connection is readable */
} /* End of if (FD_ISSET(i, &working_set)) */
} /* End of loop through selectable descriptors */
} while (end_server == FALSE);
/*************************************************************/
/* Cleanup all of the sockets that are open */
/*************************************************************/
for (i=0; i <= max_sd; ++i)
{
if (FD_ISSET(i, &master_set))
close(i);
}
}
整體看這個程式碼似曾相識,不存在抄襲,這僅僅是tcp的一種套路而已。
相關文章
- Nginx原始碼完全註釋(6)core/murmurhashNginx原始碼
- Nginx原始碼完全註釋(8)ngx_errno.cNginx原始碼
- Nginx原始碼完全註釋(5)core/ngx_cpuinfo.cNginx原始碼UI
- Nginx原始碼完全註釋(9)nginx.c: ngx_get_optionsNginx原始碼
- Nginx原始碼完全註釋(1)ngx_alloc.h / ngx_alloc.cNginx原始碼
- Nginx原始碼完全註釋(7)ngx_palloc.h/ngx_palloc.cNginx原始碼
- Nginx原始碼完全註釋(4)ngx_queue.h / ngx_queue.cNginx原始碼
- Nginx原始碼完全註釋(3)ngx_list.h / ngx_list.cNginx原始碼
- Nginx原始碼完全註釋(2)ngx_array.h / ngx_array.cNginx原始碼
- 《Linux核心完全註釋》學習筆記:2.7 Linux核心原始碼的目錄結構Linux筆記原始碼
- HashMap原始碼(JDK1.8)-手動註釋HashMap原始碼JDK
- Bootstrap的Model原始碼詳細註釋 (轉)boot原始碼
- Redux原始碼完全解讀Redux原始碼
- 【MyBatis原始碼分析】select原始碼分析及小結MyBatis原始碼
- bootstrap-modal.js學習筆記(原始碼註釋)bootJS筆記原始碼
- Dubbo原始碼解析之服務釋出與註冊原始碼
- 從Python原始碼註釋,自動生成API文件Python原始碼API
- 使用ehcache元註釋提高Spring 效能原始碼案例Spring原始碼
- C231n-KNN-assignment1-完全程式碼及註釋KNN
- C231n-SVM-assignment1-完全程式碼及註釋
- go 中 select 原始碼閱讀Go原始碼
- jQuery原始碼分析之select()方法jQuery原始碼
- Vue-Socket.io原始碼解讀Vue原始碼
- CSS程式碼註釋CSS
- php程式碼註釋PHP
- select函式socket程式設計函式程式設計
- socket程式設計的select模型程式設計模型
- maven下載原始碼,解決中文註釋為亂碼的問題Maven原始碼
- DialogFragment使用到原始碼完全解析Fragment原始碼
- Linux Socket C語言網路程式設計:Select SocketLinuxC語言程式設計
- ArcGIS VBA - VBA+AO入門15例完全註釋版
- snownlp類庫(中文情感分析)原始碼註釋及使用原始碼
- NumPyCookbook帶註釋原始碼四、連線NumPy與剩餘世界原始碼
- 從 Linux 原始碼看 socket 的 closeLinux原始碼
- Process與Socket,Select與Accept關係
- 有趣的程式碼註釋
- 請停止程式碼註釋
- javascript如何註釋程式碼JavaScript