标签:linux socket 并发服务器模型 cc++ tcp
服务器端尽可能使用SO_REUSEADDR,在绑定之前尽可能调用setsockopt来设置SO_REUSEADDR套接字选项。该选项可以使得不必等待TIME_WAIT状态消失就可以重启服务器.
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
可以在bind之前添加代码(完整代码请参照博文最后):
int optval = 1;
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) == -1)
{
err_exit("setsockopt SO_REUSEADDR error");
}用以支持地址复用.
可以从上图看出,我们的服务器最大的缺点就是无法支持多客户连接,即使客户端能够连接到服务器上,服务器也不为该客户做服务,(直接没什么反应),虽然链接是有的(也就是说,客户端是已经连接到服务器上的了,但是服务器就是不搭理你....)
从服务器的下面这段代码我们可以看出端倪....
struct sockaddr_in peerAddr;
socklen_t peerLen;
//注意:一次只能处理一个连接
int peerSockfd = accept(sockfd, (struct sockaddr *)&peerAddr,&peerLen);
if (peerSockfd == -1)
{
err_exit("accept error");
}
//打印客户信息
cout << "Client:" << endl;
cout << "\tsin_port: " << ntohs(peerAddr.sin_port) << endl;
cout << "\tsin_addr: " << inet_ntoa(peerAddr.sin_addr) << endl;
cout << "\tsocket: " << peerSockfd << endl;
//.....即服务器运行一次,只能为一个客户端服务一次!!!!
并发服务器实现
1.客户端向服务器发送请求
2.典型的(多进程)并发服务器程序框架
//完整的server端代码
#include "commen.h"
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if (sockfd == -1)
{
err_exit("socket error");
}
int optval = 1;
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) == -1)
{
err_exit("setsockopt SO_REUSEADDR error");
}
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8002);
serverAddr.sin_addr.s_addr = INADDR_ANY; //绑定本机的任意一个IP地址
//serverAddr.sin_addr.s_addr = inet_addr("10.255.218.20");
if (bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == -1)
{
err_exit("bind error");
}
//一旦调用了listen,则sockfd编程被动套接字:等待客户端的连接(只能接受连接,不能发送连接)
if (listen(sockfd,SOMAXCONN) == -1)
{
err_exit("listen error");
}
struct sockaddr_in peerAddr;
socklen_t peerLen;
while (true)
{
int peerSockfd = accept(sockfd, (struct sockaddr *)&peerAddr,&peerLen);
if (peerSockfd == -1)
{
err_exit("accept error");
}
//打印客户信息
cout << "Client:" << endl;
cout << "\tsin_port: " << ntohs(peerAddr.sin_port) << endl;
cout << "\tsin_addr: " << inet_ntoa(peerAddr.sin_addr) << endl;
cout << "\tsocket: " << peerSockfd << endl;
//每有一个客户端连接进来,就fork一个子进程,
//相应的业务处理由子进程完成,父进程继续监听
pid_t pid = fork();
if (pid == -1)
{
close(sockfd);
close(peerSockfd);
err_exit("fork error");
}
else if (pid == 0) //子进程,处理业务
{
close(sockfd); //子进程关闭监听套接字,因为子进程不负责监听任务
char buf[BUFSIZ];
memset(buf,0,sizeof(buf));
ssize_t readCount = 0;
while ((readCount = read(peerSockfd,buf,sizeof(buf))) >= 0)
{
//如果在读取数据的过程中,read返回0,则说明对方已经关闭连接
if (readCount == 0)
{
err_exit("read peerSockfd error");
}
if (write(peerSockfd,buf,readCount) == -1)
{
err_exit("write peerSockfd error");
}
buf[readCount] = ‘\0‘;
fputs(buf,stdout);
memset(buf,0,sizeof(buf));
}
}
else if (pid > 0) //父进程
{
close(peerSockfd); //父进程关闭连接套接字,因为父进程不负责为子进程服务
}
}
close(sockfd);
return 0;
}标签:linux socket 并发服务器模型 cc++ tcp
原文地址:http://blog.csdn.net/zjf280441589/article/details/41685103