Linux网络基础----多线程并发服务器(华清远见学习笔记)
网络服务器模型简介
网络服务器 常用于对后端提供网络功能,逻辑处理,数据处理的程序或者架构等;服务器常伴随着数据高连接数高吞吐量的环境中,所以对数据的及时处理的要求很高;在网络服务器模型中常见的模型有:循环服务器和并发服务器;
循环服务器
服务器依次处理每个客户端发送过来的数据,直到当前客户端的所有请求处理完成再处理下一个客户端;当服务器接收到大量的数据时,会因为服务器处理能力不足而导致客户端响应过慢;
并发服务器
创建多进程/多线程处理机制,分别为每一个客户端创建一个任务来处理,可以极大的提高服务器的并发处理能力;
TCP网络编程相关API接口图接
并发服务器服程序(TCP)
并发服务器的优势很明显的体现了出来,下面为 利用多线程实现并发服务器的代码片
.
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <pthread.h>
//创建的线程只负责接受数据
void * message_handling(void * arg)
{
int cfd = *(int *)arg;
while (1)
{
char buf[255] = {0};
int state = -1;
//接收客户端发送的数据
state = recv(cfd,buf,sizeof(buf),0);
if (-1 == state)
{
perror("子进程客户 读取数据失败");
break;
}else if (0 == state)
{
perror("子进程客户端已退出连接");
break;
}
printf("%s\n",buf);
}
pthread_exit(NULL);
}
int main(int argc,const char * argv[])
{
if (argc < 3)
{
perror("输入参数错误\n");
return -1;
}
//建立套接字
int sfd = -1;
sfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sfd)
{
perror("套接字创建失败");
return -1;
}
//绑定 服务器 IP地址与端口号
struct sockaddr_in svr;
svr.sin_family = AF_INET; //IPV4
svr.sin_addr.s_addr = inet_addr(argv[1]); //ip地址
svr.sin_port = htons(atoi(argv[2])); //端口号
//将套接字文件描述符、(服务器)端口号和ip绑定到一起
if (0 > bind(sfd,(const struct sockaddr *)&svr,sizeof(svr)))
{
perror("服务器数据绑定失败");
return -1;
}
//建立监听队列,让套接字进入到被动监听状态
if (-1 == listen(sfd,10))
{
perror("建立监听队列失败");
return -1;
}
int cfd = -1;
while (1)
{
//阻塞等待TCP连接(三次握手)
printf("主进程等待连接中...\n");
//向该主机发送方的IP
struct sockaddr_in ip;
//向该主机发送方的端口
socklen_t len = sizeof(ip);
//接受连接,产生新的套接字
cfd = accept(sfd,(struct sockaddr *)&ip,&len);
if (-1 == cfd)
{
perror("新的套接字产生失败\n");
return -1;
}
//创建线程 -----------------------------------------------
pthread_t TID = 0;//用于存放子线程的ID号
int ERROE = 0; //用于存放错误码
printf("主线程 cfd %d\n",cfd);
//创建子线程,将文件描述符号加入形参
ERROE = pthread_create(&TID,NULL,(void *)message_handling,(void *)&cfd);
if (ERROE != 0)
{
//将获取到的错误码赋值给错误码变量
errno = ERROE;
perror("子线程创建失败");
return -1;
}
//将组合式线程转换为分离式线程
pthread_detach(TID);
char * Receiving_IP = inet_ntoa(ip.sin_addr); //将获取到的ip(网络字节序)转换为字符串
int Receiving_port = ntohs(ip.sin_port); //将获取到的端口(网络字节序)转换为十进制数
//printf("\n<<<================================================\n");
printf("\t客户端成功连接服务器\n\n");
printf("\t客户端IP\t:%s\n",Receiving_IP);
printf("\t客户端端口\t:%d\n",Receiving_port);
printf("\t线程TID号\t:%ld\n",TID);
printf("================================================>>>\n\n");
}
return 0;
}