基于流模式长连接的简单实现
基于流模式的长连接我们可以做很多事情,比方说在局域网内,我们建立这种模式,可以时时传输数据,而不用每次传输数据是创建socket,传输完后,关闭socket。可以减少创建销毁socket的时间。基于流模式的下,数据一直在发送,我们需要知道,每次发送数据量,所以常见的方式时,我们在发送数据时,指定此次发送数据的长度,服务器读取流数据时,先读取数据长度,然后再按长度读取此次发送的数据。
我使用select复用IO机制实现了一个简单的client,server机制,希望对初学者有帮助
客户端代码:
- /*
- * =====================================================================================
- *
- * Filename: client.cc
- * Description:
- * Version: 1.0
- * Created: 2008年12月18日 09时50分36秒 CST
- * Revision: none *
- * Author: ugg (ugg_xchj@yahoo.com.cn)
- * Company:
- *
- * =====================================================================================
- */
- #include <string>
- #include <iostream>
- #include <netdb.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- using namespace::std;
- // 默认内容设置
- string hostname="localhost";
- int hostport=7763;
- string sendContents="this is client";
- void getCMD(int argc, char *argv[])
- {
- switch(argc)
- {
- case 2:
- hostname = argv[1];
- break;
- case 3:
- hostname = argv[1];
- hostport = atoi(argv[2]);
- if(hostport < 1024 || hostport >65535)
- {
- cerr << "Error: port=" << hostport
- << " Error, range 1024 - 65535" << endl;
- exit(0);
- }
- break;
- case 4:
- hostname = argv[1];
- hostport = atoi(argv[2]);
- if(hostport < 1024 || hostport >65535)
- {
- cerr << "Error: port=" << hostport
- << " Error, range 1024 - 65535" << endl;
- exit(0);
- }
- sendContents = argv[3];
- break;
- default:
- break;
- }
- }
- int
- main ( int argc, char *argv[] )
- {
- getCMD(argc,argv);
- int fd;
- // create socket
- if((fd=socket(PF_INET,SOCK_STREAM,0)) == -1)
- {
- cerr << "Error: socket()" <<endl;
- exit(0);
- }
- //
- struct hostent *he;
- he = gethostbyname(hostname.c_str());
- if(he == NULL ) {
- cerr <<"Error: gethostbyname() error,hostname=" << hostname << endl;
- exit(0);
- }
- struct sockaddr_in serv_addr;
- serv_addr.sin_family=AF_INET;
- serv_addr.sin_port=htons(hostport);
- serv_addr.sin_addr=*((struct in_addr*)he->h_addr);
- bzero( &(serv_addr.sin_zero),8);
- // connction
- if(connect(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1) {
- cerr<<"Error: connect() error"<<endl;
- exit(0);
- }
- cout << "send contents to server(" << hostname
- << ":" << hostport << ")" << endl;
- cout << sendContents << endl;
- cout << "................" << endl;
- // 增加此次发送消息的长度
- char buffer[1024];
- sprintf(buffer,"%8d",sendContents.length());
- sendContents = string(buffer,8)+sendContents;
- const char* content = sendContents.c_str();
- int send=0;
- int length = sendContents.length();
- // send
- while(1)
- {
- int ret = write(fd,content+send,length-send);
- if(ret == 0)
- {
- // server close
- cerr << "Error: server close" << endl;
- exit(0);
- }
- send += ret;
- if(length == send)
- break;
- }
- string contents;
- // 先接受8字节,获取服务返回长度
- int ret = recv(fd,buffer,8,0);
- // 服务器关闭
- if(ret == 0)
- {
- cerr << "Error: server close" << endl;
- exit(0);
- }
- if(ret == 8)
- {
- buffer[8]='/0';
- int len = atoi(buffer);
- if(len < 1024){
- int rets=0;
- while((ret = recv(fd,buffer,len-rets,0))>0)
- {
- contents.append(buffer,ret);
- rets += ret;
- if(len==rets)
- break;
- }
- }else{
- int buflen=1024;
- while( (ret = recv(fd,buffer,buflen,0)) > 0)
- {
- contents.append(buffer,ret);
- len-=ret;
- if(len<2048){
- buflen=len;
- }
- if(len <= 0)
- break;
- }
- }
- }else {
- cerr << "Error: recv data Error " << endl;
- }
- cout << "recv: ";
- cout << contents << endl;
- return 0;
- } /* ---------- end of function main ---------- */
- /*
- * =====================================================================================
- *
- * Filename: server.cc
- * Description:
- * Version: 1.0
- * Created: 2008年12月18日 09时50分50秒 CST
- * Revision: none *
- * Author: ugg (ugg_xchj@yahoo.com.cn)
- * Company:
- *
- * =====================================================================================
- */
- #include <string>
- #include <iostream>
- #include <netdb.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <errno.h>
- #include <map>
- using namespace::std;
- struct clientInfo
- {
- string host;
- int port;
- };
- typedef map<int, clientInfo> mapgroups;
- typedef map<int, clientInfo>::iterator mapgroupsor;
- typedef map<int, clientInfo>::const_iterator mapgroupscor;
- // 记录客户端的信息
- mapgroups groups;
- // 默认内容设置
- string hostname="localhost";
- int hostport=7763;
- string serversendContents="this is server";
- void getCMD(int argc, char *argv[])
- {
- switch(argc)
- {
- case 2:
- hostname = argv[1];
- break;
- case 3:
- hostname = argv[1];
- hostport = atoi(argv[2]);
- if(hostport < 1024 || hostport >65535)
- {
- cerr << "Error: port=" << hostport
- << " Error, range 1024 - 65535" << endl;
- exit(0);
- }
- break;
- case 4:
- hostname = argv[1];
- hostport = atoi(argv[2]);
- if(hostport < 1024 || hostport >65535)
- {
- cerr << "Error: port=" << hostport
- << " Error, range 1024 - 65535" << endl;
- exit(0);
- }
- serversendContents = argv[3];
- break;
- default:
- break;
- }
- }
- void clearfd(int fd,fd_set& rdfds)
- {
- FD_CLR(fd,&rdfds);
- mapgroupsor it = groups.find(fd);
- if(it != groups.end())
- {
- cerr << "client host=" << it->second.host << ", port=" << it->second.port
- << " close" << endl;
- groups.erase(fd);
- }
- }
- // recv and send message
- void recvandsend(int fd,fd_set& rdfds,string& contents, const string& texts)
- {
- // 接受消息
- char buffer[1024];
- int rets=0;
- int ret=0;
- ret = recv(fd,buffer,8,0);
- if(ret == 0)
- {
- clearfd(fd,rdfds);
- return;
- }
- if(ret == 8)
- {
- buffer[8]='/0';
- int len = atoi(buffer);
- if(len < 1024){
- while((ret = recv(fd,buffer,len,0))>0)
- {
- contents.append(buffer,ret);
- rets += ret;
- len-=ret;
- if(len==0)
- break;
- }
- if(ret == 0){
- clearfd(fd,rdfds);
- return;
- }
- }else{
- int buflen=1024;
- while( (ret = recv(fd,buffer,buflen,0)) > 0)
- {
- contents.append(buffer,ret);
- rets += ret;
- len-=ret;
- if(len<2048){
- buflen=len;
- }
- if(len <= 0)
- break;
- }
- if(ret == 0){
- clearfd(fd,rdfds);
- return;
- }
- }
- }else{
- clearfd(fd,rdfds);
- return;
- }
- // 发送信息
- sprintf(buffer,"%8d",texts.length());
- string sendContents = string(buffer,8);
- sendContents += texts;
- const char* content = sendContents.c_str();
- int send=0;
- int length = sendContents.length();
- // send
- while(1)
- {
- int ret = write(fd,content+send,length-send);
- if(ret == 0)
- {
- // server close
- cerr << "Error: server close" << endl;
- clearfd(fd,rdfds);
- return;
- }
- send += ret;
- if(length == send)
- break;
- }
- }
- int
- main ( int argc, char *argv[] )
- {
- getCMD(argc,argv);
- int fd;
- // create socket
- if((fd=socket(PF_INET,SOCK_STREAM,0)) == -1)
- {
- cerr << "Error: socket()" <<endl;
- exit(0);
- }
- //
- struct hostent *he;
- he = gethostbyname(hostname.c_str());
- if(he == NULL ) {
- cerr <<"Error: gethostbyname() error,hostname=" << hostname << endl;
- exit(0);
- }
- struct sockaddr_in serv_addr;
- serv_addr.sin_family=AF_INET;
- serv_addr.sin_port=htons(hostport);
- serv_addr.sin_addr=*((struct in_addr*)he->h_addr);
- bzero( &(serv_addr.sin_zero),8);
- // bind
- if(bind(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1) {
- cerr<<"Error: bind() error"<<endl;
- exit(0);
- }
- // listen
- int ret_listen = listen(fd,5);
- if(ret_listen < 0)
- {
- cerr << "Error: Listen port error,socket fd: " << fd << endl;
- cerr << "Error: listen errno = " << ret_listen << endl;
- exit(0);
- }
- fd_set rdfds;
- int nfds;
- // First poll the sockets
- FD_ZERO(&rdfds);
- FD_SET(fd, &rdfds);
- while(1)
- {
- if ((nfds = select(FD_SETSIZE, &rdfds, NULL, NULL, NULL)) < 0) {
- if (errno != EINTR) {
- cerr << "Error: select error" << endl;
- exit(3);
- }
- }
- if(FD_ISSET(fd, &rdfds))
- {
- socklen_t len;
- struct sockaddr_in client_addr;
- len = sizeof(struct sockaddr);
- int clientfd = accept(fd,(struct sockaddr *)&client_addr,&len);
- if(clientfd == -1)
- {
- cerr << "Error: accept client error" << endl;
- }else{
- clientInfo info;
- info.host = inet_ntoa(client_addr.sin_addr);
- info.port = ntohs(client_addr.sin_port);
- cerr << "server: got connection from "<< info.host
- <<", port "<< info.port << endl;
- groups.insert(make_pair(clientfd,info));
- FD_SET(clientfd,&rdfds);
- }
- }else{
- mapgroupscor it;
- for(it = groups.begin(); it != groups.end(); ++it)
- {
- if(FD_ISSET(it->first,&rdfds))
- {
- string strRev;
- recvandsend(it->first,rdfds,strRev,serversendContents);
- break;
- }
- }
- }
- }
- return 0;
- } /* ---------- end of function main ---------- */
另外你可以到这里下载源代码
最后更新:2017-04-02 00:06:39