一步一步学习Unix编程[2]——迭代服务器

转载请注明t1234xy4原创:http://blog.csdn.net/t1234xy4/article/details/51925011

1、迭代服务器

所谓迭代服务器就是处理完一个客服端请求后,接着再处理第二个客服端请求,如果没有请求服务器将阻塞在accept处,直到有请求传来。

2、自定义头文件


在编代码前,需要先介绍自定义的一个头文件:MyIncludding.h
/*
 * MyIncluding.h
 *
 *  Created on: Jul 11, 2016
 *      Author: ubuntu
 */

#ifndef HEADER_MYINCLUDING_H_
#define HEADER_MYINCLUDING_H_

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define  MAXLINE 1024
#define  FIFO_MODE (S_IRUSR | S_IWUSR | S_IRGRP |S_IROTH)

#define SERV_PORT 		9877
#define SA  			struct sockaddr
#define LISTENQ         1024

#endif /* HEADER_MYINCLUDING_H_ */
此处定义了服务器的监听端口SERV_PORT = 9877,服务器将使用这个端口监听。
同时定义了服务器监听的客户端请求的总个数 LISTENQ。LISTENQ包括了服务器端已建立连接的队列和未建立连接队列的总和。
已建立链接队列中保存了客户端与服务器端完成了TCP三路握手,这些链接处于ESTABLISHED状态,但没有服务器还没有accept此链接。
未建立连接队列中保存未客户端与服务器端还没有建立连接,客户的连接请求刚刚到达服务器,也就是三路握手的第一步。此时链接处于SYN_RCVD状态。如果三路握手正常完成将插入到已连接队列后。如果链接进入为建立连接队列超过一个RTT(往返时间)则被丢弃(因为重传机制,如果不丢弃将可能与该客户端建立两次链接或者更多)。

3、服务器端源码

/*
 * ServiceFork.cpp
 *
*  Created on: Jul 15, 2016
 *      Author: ubuntu
 */
#include <iostream>
#include "MyIncluding.h"

using namespace std;
char serv_ip[16] = "172.25.9.94"; //本地IP地址

int main(int argc,char** argv)
{
	int listenfd,connfd;
	pid_t childpid;
	struct sockaddr_in cliaddr,servaddr;

	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	inet_pton(AF_INET,serv_ip,&servaddr.sin_addr);
	servaddr.sin_port = htons(SERV_PORT);

	listenfd = socket(AF_INET,SOCK_STREAM,0);

	int nbind = bind(listenfd,(SA *)&servaddr,sizeof(servaddr));

	int nlisten = listen(listenfd,LISTENQ);

	while(1)
	{
		socklen_t cliaddrlen= sizeof(cliaddr);
		connfd = accept(listenfd,(SA *)&cliaddr,&cliaddrlen);
		if(connfd<0)
		<span style="white-space:pre">	</span>cout <<"accept error!"<<endl;
<span style="white-space:pre">		</span>else{
		<span style="white-space:pre">	</span>char buff[1024];
			int nread = read(connfd,buff,sizeof(buff));
			if( nread > 0 )
				cout<< "receive MSG:"<<buff<<endl;
		<span style="white-space:pre">	</span><span style="font-family: Arial, Helvetica, sans-serif;">close(connfd);</span>
		}
	}
}

此服务器端很简单,就与客户端建立连接,然后接受客户端传来的消息打印出来。
那么客户端应该做的事是与服务器建立连接,然后传一条消息过去。

4、客户端代码

为了便于扩展,我将客户端封装为一个SimClient类:
SimClient.h
<pre name="code" class="cpp">/*
 * SimClient.h
 *
 *  Created on: Jul 13, 2016
 *      Author: ubuntu
 */

#ifndef SIMCLIENT_H_
#define SIMCLIENT_H_

#include "MyIncluding.h"
#include "IOoperater.h"
#include <iostream>
#include <fcntl.h>

using namespace std;

class SimClient {

public:
	SimClient();
	bool virtual connectServer();
	virtual bool run();
	void setClientId(int i){_clientId = i ;}
<span>	</span>virtual bool stopRunning();
	virtual bool reRun();
	virtual ~SimClient();

protected:
	int sockfd;
	char* buf;
	struct sockaddr_in serviceaddr;
<span>	</span>int _clientId;
};

#endif /* SIMCLIENT_H_ */

 SimClient.cpp 
/*
 * SimClient.cpp
 *
 *  Created on: Jul 13, 2016
 *      Author: ubuntu
 */

#include "SimClient.h"

SimClient::SimClient():sockfd(-1),_clientId(-1){
	// TODO Auto-generated constructor stub
	buf = new char[1];
	strcpy(buf,"\0");
}

bool SimClient::connectServer()
{
	sockfd = socket(AF_INET,SOCK_STREAM,0);

	bzero(&serviceaddr,sizeof(serviceaddr));
	serviceaddr.sin_family = AF_INET;
	char mySERV_IP[16] ="172.25.9.94";
	inet_pton(AF_INET,mySERV_IP,&serviceaddr.sin_addr);
	//serviceaddr.sin_addr = htonl(SERV_IP);
	serviceaddr.sin_port = htons(SERV_PORT);

	int connectret;
		connectret = connect(sockfd,(SA *)&serviceaddr,sizeof(serviceaddr));
		if(connectret<0)
		{
			cout << "connection error,errno="<<errno<<","<<strerror(errno)<<endl;
			return false;
		}
	return true;
}

bool SimClient::run()
{
	char msg[1024];
<span style="white-space:pre">	</span>time_t ticks = time(NULL);
<span style="white-space:pre">	</span>snprintf(msg,sizeof(msg),"client %d access at: %.24s",_clientId,ctime(&ticks));
<span style="white-space:pre">	</span>int nwrite = write(sockfd,msg,strlen(msg));
<span style="white-space:pre">	</span>if(nwrite < 0)
<span style="white-space:pre">		</span>cout << "Message send failure ************"<<endl;
<span style="white-space:pre">	</span>else
<span style="white-space:pre">		</span>cout << "Message: "<<msg << ", sended!"<<endl;
}


bool SimClient::reRun()
{

	return true;
}

bool SimClient::stopRunning()
{

	return true;
}

SimClient::~SimClient() {
	// TODO Auto-generated destructor stub
	if(buf)
		free(buf);
	close(sockfd);
}
客户端调用入口:
//============================================================================
// Name        : SimClient.cpp
// Author      : Tian
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include "SimClient.h"
using namespace std;

int main() {
	cout << "!!!!!!thread Test is running!!!!!!" << endl; 
	sleep(1);
	SimClient *thread = new SimClient;
	thread->setThreadId(i);
	if (!thread->connectServer())
	{
		cout << "thread "<< i << "failed!"<<endl;
		continue;
	}
	cout << endl <<"connected :"<< thread->getThreadId()<<endl;
	thread->run();
	cout << thread->getThreadId() <<" shutdown !";

	delete thread;
	return 0;
}

总结:

服务端:socket()->bind()->listen()->accept()(阻塞)->read()
客户端:socket()->connect()->write()
结果是服务器端收到客服端的Id以及时间信息。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值