基於流模式長連接的簡單實現
基於流模式的長連接我們可以做很多事情,比方說在局域網內,我們建立這種模式,可以時時傳輸數據,而不用每次傳輸數據是創建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