TCP服务器和客户端的链接例子(侧重点在注意关闭套接子,减少套接子的描述子)
每个文件或套接口都有一个访问计数,该访问计数在文件表项中维护,它表示当前指向该文件或套接口的打开的描述字个数。
每个文件,套接口都有一个访问计数器,表示当前指向该文件或套接口的打开的描述子个数。从accpet返回后client_fd关联的文件表项访问计数值为1,从socket返回后,与sockfd的关联的文件表项访问计数值为1;但是,当fork返回后,两个描述子在父进程和子进程复制,所以,与两个套接口相关联的文件表项访问计数值均为2.当父进程关闭client_fd时,只是将访问计数值从2减少为1。描述字在访问记数值为0时才真正关闭。
如果父进程从未关闭accpet返回的已经链接套接口调用close。父进程最终将耗尽可用描述子,因为任何进程在某个时刻打开的描述子数是有限的。更重要的是没有一个客户链接被终止。如果父进程从未关闭已经链接套接口,这将防挨TCP链接终止序列的执行,从而链接永远保持开发。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#define MAXDATASIZE 100
#define SERVPORT 3333 /*服务器监听端口号 */
#define BACKLOG 10 /* 最大同时连接请求数 */
int main()
{
pid_t pid;
char line[100];
ssize_t n;
int recvbytes,nfds,i,epfd;
char buf[100];
char ref[100];
int sockfd,client_fd; /*sock_fd:监听socket;client_fd:数据传输socket */
int sockfds;
//声明epoll_event结构体变量,ev用于注册事件,数组用于回传要处理的事件
//epoll_event被用于注册所感兴趣的事件和回传所发生的待处理事件
struct epoll_event ev,events[20];
epfd = epoll_create(256);//256这个参数可以改变(网上看到过有设为5000)
struct sockaddr_in my_addr; /* 本机地址信息 */
struct sockaddr_in remote_addr; /* 客户端地址信息 */
socklen_t sin_size;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket创建出错!"); exit(1);
}
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(SERVPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero),8);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind出错!");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) //BACKLOG有最大数值限制,超过这个数值时出现ECONNREFUSEd错误
{
perror("listen出错!");
exit(1);
}
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1)
{
perror("accept出错");
exit(0);
//continue;
}
if((pid=fork())==0)
{
close(sockfd);
printf("1: client_fd: %d; sockfd: %d\n",client_fd,sockfd);
bzero(buf,100);
strcpy(buf,"Client has connected Server!");
strcat(buf,"\n");
if(-1==send(client_fd,buf,100,0))
{
printf("Err:send failed <%s> %s\n",buf,strerror(errno));
exit(1);
}
//close(client_fd);
exit(0);
}
close(client_fd);
waitpid(-1,NULL,WNOHANG);
printf("2: client_fd: %d; sockfd: %d\n",client_fd,sockfd);
}
}
#include<stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#define SERVPORT 3333
#define MAXDATASIZE 100 /*每次最大数据传输量 */
int main(int argc, char *argv[])
{
int sockfd, recvbytes;
char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr;
char * argvs = "5000790-1";
if((host=gethostbyname(argvs))==NULL)
{
herror("gethostbyname出错!");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket创建出错!");
exit(1);
}
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERVPORT);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect出错!");
exit(1);
}
for(int i=0; i<1; i++)
{
printf("%d client is ready to recv buf! \n",i);
if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1)
{
perror("recv出错!");
exit(1);
}
buf[recvbytes] = '\0';
printf("%d Received: %s\n",i,buf);
memset(buf,0,100);
}
close(sockfd);
}
每个文件或套接口都有一个访问计数,该访问计数在文件表项中维护,它表示当前指向该文件或套接口的打开的描述字个数。
每个文件,套接口都有一个访问计数器,表示当前指向该文件或套接口的打开的描述子个数。从accpet返回后client_fd关联的文件表项访问计数值为1,从socket返回后,与sockfd的关联的文件表项访问计数值为1;但是,当fork返回后,两个描述子在父进程和子进程复制,所以,与两个套接口相关联的文件表项访问计数值均为2.当父进程关闭client_fd时,只是将访问计数值从2减少为1。描述字在访问记数值为0时才真正关闭。
如果父进程从未关闭accpet返回的已经链接套接口调用close。父进程最终将耗尽可用描述子,因为任何进程在某个时刻打开的描述子数是有限的。更重要的是没有一个客户链接被终止。如果父进程从未关闭已经链接套接口,这将防挨TCP链接终止序列的执行,从而链接永远保持开发。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#define MAXDATASIZE 100
#define SERVPORT 3333 /*服务器监听端口号 */
#define BACKLOG 10 /* 最大同时连接请求数 */
int main()
{
pid_t pid;
char line[100];
ssize_t n;
int recvbytes,nfds,i,epfd;
char buf[100];
char ref[100];
int sockfd,client_fd; /*sock_fd:监听socket;client_fd:数据传输socket */
int sockfds;
//声明epoll_event结构体变量,ev用于注册事件,数组用于回传要处理的事件
//epoll_event被用于注册所感兴趣的事件和回传所发生的待处理事件
struct epoll_event ev,events[20];
epfd = epoll_create(256);//256这个参数可以改变(网上看到过有设为5000)
struct sockaddr_in my_addr; /* 本机地址信息 */
struct sockaddr_in remote_addr; /* 客户端地址信息 */
socklen_t sin_size;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket创建出错!"); exit(1);
}
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(SERVPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero),8);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind出错!");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) //BACKLOG有最大数值限制,超过这个数值时出现ECONNREFUSEd错误
{
perror("listen出错!");
exit(1);
}
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1)
{
perror("accept出错");
exit(0);
//continue;
}
if((pid=fork())==0)
{
close(sockfd);
printf("1: client_fd: %d; sockfd: %d\n",client_fd,sockfd);
bzero(buf,100);
strcpy(buf,"Client has connected Server!");
strcat(buf,"\n");
if(-1==send(client_fd,buf,100,0))
{
printf("Err:send failed <%s> %s\n",buf,strerror(errno));
exit(1);
}
//close(client_fd);
exit(0);
}
close(client_fd);
waitpid(-1,NULL,WNOHANG);
printf("2: client_fd: %d; sockfd: %d\n",client_fd,sockfd);
}
}
#include<stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#define SERVPORT 3333
#define MAXDATASIZE 100 /*每次最大数据传输量 */
int main(int argc, char *argv[])
{
int sockfd, recvbytes;
char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr;
char * argvs = "5000790-1";
if((host=gethostbyname(argvs))==NULL)
{
herror("gethostbyname出错!");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket创建出错!");
exit(1);
}
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERVPORT);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect出错!");
exit(1);
}
for(int i=0; i<1; i++)
{
printf("%d client is ready to recv buf! \n",i);
if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1)
{
perror("recv出错!");
exit(1);
}
buf[recvbytes] = '\0';
printf("%d Received: %s\n",i,buf);
memset(buf,0,100);
}
close(sockfd);
}