Linux系统编程73 网络编程7 - 流式套接字_并发版

流式套接字 并发版:
如果多个C端向S端请求数据,并且服务时间较长,那么以单进程执行的话,那么多个请求,效率非常低,所以改进为 并发版本

server.c

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include "proto.h"

#define IPSTRSIZE 40
#define BUFSIZE 1024


static void server_job(int sd)
{
	char buf[BUFSIZE];
	int len;
	
//将时间戳 以 FMT_STAMP格式 存储到 buf中
	len = sprintf(buf,FMT_STAMP,(long long)time(NULL));
	
	if(send(sd,buf,len,0) < 0)
	{
		perror("send()");
		exit(1);
	}
//sleep(10);
}


int main()
{
	int sd,newsd;

	struct sockaddr_in laddr,raddr;
	socklen_t raddr_len;
	char ipstr[IPSTRSIZE];

//取得SOCKET, 用 AF_INET协议族中 默认支持流式套接字的协议(IPPROTO_TCP) 来完成流式套接字传输,
	sd = socket(AF_INET,SOCK_STREAM,0/*IPPROTO_TCP*/);
	if(sd < 0)
	{
		perror("soccket()");
		exit(1);
	}


//对指定Socket sd 的SOL_SOCKET层面 的 SO_REUSEADDR属性进行设置,即打开该属性,如果发现 端口没有释放,该属性会马上释放该端口,并且让我们绑定成功。
	int val = 1;
	if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,&val, sizeof(val)) < 0)
	{
		perror("setsockopt()");
		exit(1);
	}

 //设置 AF_INET 协议族地址信息结构体,AF_INET 协议族中的 协议地址类型为 struct sockaddr_in 

	laddr.sin_family = AF_INET; // 协议族为 AF_INET 
 // 设置端口为1989,因为需要将自己的地址信息(包括端口信息)发出去,所以需要注意字节序问题,即 从主机发向网络,htons
	laddr.sin_port = htons(atoi(SERVERPORT));
 // 设置IP 
	inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);//0.0.0.0:any address

// 给SOCKET绑定一个地址,关联到目标协议族地址信息结构体,即绑定IP,端口
//(void *)&laddr, 实际并没有struct sockaddr类型,所以暂时强转为 void *
	if(bind(sd,(void *)&laddr,sizeof(laddr)) < 0)
	{
		perror("bind");
		exit(1);
	}

//将socket置为监听模式, 承受C端最大数量为200
	if(listen(sd,200) < 0)
	{
		perror("listen");
		exit(1);	
	}

	/* !!!! */
	raddr_len = sizeof(raddr);

	while(1)
	{
   //接受连接,保存对端地址信息,如果成功,将返回一个非负整数,它是所接受套接字的描述符,即newsd 
  //默认为阻塞等待连接
		newsd = accept(sd,(void *)&raddr,&raddr_len);
		if(newsd < 0)
		{
			perror("accept");
			exit(1);	
		}

pid = fork();//创建子进程
		if(pid < 0)
		{
			perror("fork()");
			exit(1);
		}
	
//子进程
if(pid == 0)
{
close(sd); //关闭子进程不用的 文件描述符,避免相互影响!!!

 //将接收到的对端地址中IP信息 从大整数 转换为 点分式 保存到ipstr数组
		inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE);

//打印对端 IP:端口
//raddr.sin_port  是从socket接收到的信息,不是单字节信息,需要字节序转换 ntohs
		printf("Client %s:%d\n",ipstr,ntohs(raddr.sin_port));

		server_job(newsd);
		close(newsd);
		exit(0);//结束子进程
		
}
close(newsd);//关闭父进程不用的文件描述符 避免相互影响!!!
}	

	close(sd);

	exit(0);

}

Guess you like

Origin blog.csdn.net/LinuxArmbiggod/article/details/115499782