一、模型
服务器模型可以分:
循环服务器:在同一时刻只能相应一个客户端的请求
并发服务器:在同一时刻可以相应多个客户端的请求
二、基础的TCP循环服务器
服务器端:
#include
#include
#include
#include
#include
#include
#include
#include
#include
//ERRLOG的宏定义
#define ERRLOG(errmsg) do{\
perror(errmsg);\
printf("%s--%s--(%d)\n",__FILE__,__func__,__LINE__);\
exit(-1);\
}while(0)
int main(int argc,char *argv[])
{
if(3!=argc)
{
printf("Usage: %s \n",argv[0]);
}
//创建套接字
int sockfd =0;
if((sockfd=socked(AF_INET,SOCK_STREAM,0))==-1)
{
ERRLOG("socket error");
}
//填充服务器网络信息结构体
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
//绑定套接字和网络信息结构体
socklen_t addrlen =sizeof(serveraddr);
if(bind(sockfd,(struct sockaddr *)&serveraddr,addrlen)==-1)
{
ERRLOG("bind error");
}
//将套接字设置成为被监听状态
if(listen(sockfd,5)==-1)
{
ERRLOG("listen error");
}
//定义结构体来保护客户端的网络地址结构的结构体
struct sockaddr_in clientaddr;
socklen_t client_addrlen =sizeof(clientaddr);
char buff[128]={0};
int ret=0;
//循环体
while(1)
{
printf("正在等待客户端连接\n");
int acceptfd=accept(sockfd,(struct sockaddr *)&clientaddr,&client_addrlen);
if(acceptfd==-1)
{
ERRLOG("accept error");
}
printf("%s--%d 已经连接\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
while(1)
{
if(-1 == (ret = recv(acceptfd, buff, 128, 0)))
{
ERRLOG("recv error");
}
else if(0 == ret)
{
printf("客户端--%s(%d)--断开了连接\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
break;
}
else if(!strcmp(buff, "quit"))
{
printf("客户端--%s(%d)--退出了\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
break;
}
printf("%s(%d):%s\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port), buff);
strcat(buff, "--nihao");
send(acceptfd, buff, 128, 0);
}
close(acceptfd);
}
return 0;
}
客户端:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERRLOG(errmsg) do{\
perror(errmsg);\
printf("%s--%s--(%d)\n",__FILE__,__func__,__LINE__);\
exit(-1);\
}while(0)
int main(int argc, char *argv[])
{
if(3 != argc)
{
printf("Usage: %s \n", argv[0]);
exit(-1);
}
//创建套接字
int sockfd = 0;
if(-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0)))
{
ERRLOG("socket error");
}
//填充服务器网络信息结构体
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
//与服务器建立连接
socklen_t addrlen = sizeof(serveraddr);
if(-1 == connect(sockfd, (struct sockaddr *)&serveraddr, addrlen))
{
ERRLOG("connect error");
}
printf("与服务器连接成功\n");
char buff[128] = {0};
int ret = 0;
//循环体
while(1)
{
scanf("%s", buff);
if(-1 == send(sockfd, buff, 128, 0))
{
ERRLOG("send error");
}
if(!strcmp(buff, "quit"))
{
break;
}
memset(buff, 0, 128);
if(-1 == recv(sockfd, buff, 128, 0))
{
ERRLOG("recv error");
}
printf("recv: %s\n",buff);
}
close(sockfd);
return 0;
}
三、实现TCP并发服务器的三种方法
多进程实现TCP并发服务器
多线程实现TCP并发服务器
IO多路复用实现TCP并发服务器
华清远见学习笔记整理(3)