转载请注明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以及时间信息。