基於流模式的長連接我們可以做很多事情,比方說在局域網內,我們建立這種模式,可以時時傳輸數據,而不用每次傳輸數據是創建socket,傳輸完後,關閉socket。可以減少創建銷毀socket的時間。
基於流模式的下,數據一直在發送,我們需要知道,每次發送數據量,所以常見的方式時,我們在發送數據時,指定此次發送數據的長度,服務器讀取流數據時,先讀取數據長度,然後再按長度讀取此次發送的數據。
我使用select復用IO機制實現了一個簡單的client,server機制,希望對初學者有幫助
客戶端代碼:
1./*
2. * ==================================================================
3. *
4. * Filename: client.cc
5. * Description:
6. * Version: 1.0
7. * Created: 2008年12月18日 09時50分36秒 CST
8. * Revision: none *
9. * Author: ugg (ugg_xchj@yahoo.com.cn)
10. * Company:
11. *
12. * ==================================================================
13. */
14.
15.#include <string>
16.#include <iostream>
17.#include <netdb.h>
18.#include <sys/socket.h>
19.#include <sys/types.h>
20.#include <netinet/in.h>
21.#include <arpa/inet.h>
22.
23.using namespace::std;
24.
25.// 默認內容設置
26.string hostname="localhost";
27.int hostport=7763;
28.string sendContents="this is client";
29.
30.void getCMD(int argc, char *argv[])
31.{
32. switch(argc)
33. {
34. case 2:
35. hostname = argv[1];
36. break;
37. case 3:
38. hostname = argv[1];
39. hostport = atoi(argv[2]);
40. if(hostport < 1024 || hostport >65535)
41. {
42. cerr << "Error: port=" << hostport
43. << " Error, range 1024 - 65535" << endl;
44. exit(0);
45. }
46. break;
47. case 4:
48. hostname = argv[1];
49. hostport = atoi(argv[2]);
50. if(hostport < 1024 || hostport >65535)
51. {
52. cerr << "Error: port=" << hostport
53. << " Error, range 1024 - 65535" << endl;
54. exit(0);
55. }
56. sendContents = argv[3];
57. break;
58. default:
59. break;
60. }
61.}
62.
63.int
64.main ( int argc, char *argv[] )
65.{
66. getCMD(argc,argv);
67.
68. int fd;
69. // create socket
70. if((fd=socket(PF_INET,SOCK_STREAM,0)) == -1)
71. {
72. cerr << "Error: socket()" <<endl;
73. exit(0);
74. }
75. //
76. struct hostent *he;
77. he = gethostbyname(hostname.c_str());
78. if(he == NULL ) {
79. cerr <<"Error: gethostbyname() error,hostname=" << hostname << endl;
80. exit(0);
81. }
82.
83. struct sockaddr_in serv_addr;
84.
85. serv_addr.sin_family=AF_INET;
86. serv_addr.sin_port=htons(hostport);
87. serv_addr.sin_addr=*((struct in_addr*)he->h_addr);
88. bzero( &(serv_addr.sin_zero),8);
89.
90. // connction
91. if(connect(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1) {
92. cerr<<"Error: connect() error"<<endl;
93. exit(0);
94. }
95.
96. cout << "send contents to server(" << hostname
97. << ":" << hostport << ")" << endl;
98. cout << sendContents << endl;
99. cout << "................" << endl;
100.
101. // 增加此次發送消息的長度
102. char buffer[1024];
103. sprintf(buffer,"%8d",sendContents.length());
104.
105. sendContents = string(buffer,8)+sendContents;
106.
107. const char* content = sendContents.c_str();
108. int send=0;
109. int length = sendContents.length();
110.
111. // send
112. while(1)
113. {
114. int ret = write(fd,content+send,length-send);
115. if(ret == 0)
116. {
117. // server close
118. cerr << "Error: server close" << endl;
119. exit(0);
120. }
121. send += ret;
122. if(length == send)
123. break;
124. }
125.
126. string contents;
127. // 先接受8字節,獲取服務返回長度
128. int ret = recv(fd,buffer,8,0);
129. // 服務器關閉
130. if(ret == 0)
131. {
132. cerr << "Error: server close" << endl;
133. exit(0);
134. }
135. if(ret == 8)
136. {
137. buffer[8]='\0';
138. int len = atoi(buffer);
139. if(len < 1024){
140. int rets=0;
141. while((ret = recv(fd,buffer,len-rets,0))>0)
142. {
143. contents.append(buffer,ret);
144. rets += ret;
145. if(len==rets)
146. break;
147. }
148. }else{
149. int buflen=1024;
150. while( (ret = recv(fd,buffer,buflen,0)) > 0)
151. {
152. contents.append(buffer,ret);
153. len-=ret;
154. if(len<2048){
155. buflen=len;
156. }
157. if(len <= 0)
158. break;
159. }
160. }
161. }else {
162. cerr << "Error: recv data Error " << endl;
163. }
164.
165. cout << "recv: ";
166. cout << contents << endl;
167.
168. return 0;
169.} /* ---------- end of function main ---------- */
服務器端代碼
1./*
2. * =====================================================================================
3. *
4. * Filename: server.cc
5. * Description:
6. * Version: 1.0
7. * Created: 2008年12月18日 09時50分50秒 CST
8. * Revision: none *
9. * Author: ugg (ugg_xchj@yahoo.com.cn)
10. * Company:
11. *
12. * =====================================================================================
13. */
14.#include <string>
15.#include <iostream>
16.#include <netdb.h>
17.#include <sys/socket.h>
18.#include <sys/types.h>
19.#include <netinet/in.h>
20.#include <arpa/inet.h>
21.#include <errno.h>
22.#include <map>
23.
24.using namespace::std;
25.
26.struct clientInfo
27.{
28. string host;
29. int port;
30.};
31.
32.typedef map<int, clientInfo> mapgroups;
33.typedef map<int, clientInfo>::iterator mapgroupsor;
34.typedef map<int, clientInfo>::const_iterator mapgroupscor;
35.
36.// 記錄客戶端的信息
37.mapgroups groups;
38.
39.// 默認內容設置
40.string hostname="localhost";
41.int hostport=7763;
42.string serversendContents="this is server";
43.44.void getCMD(int argc, char *argv[])
45.{
46. switch(argc)
47. {
48. case 2:
49. hostname = argv[1];
50. break;
51. case 3:
52. hostname = argv[1];
53. hostport = atoi(argv[2]);
54. if(hostport < 1024 || hostport >65535)
55. {
56. cerr << "Error: port=" << hostport
57. << " Error, range 1024 - 65535" << endl;
58. exit(0);
59. }
60. break;
61. case 4:
62. hostname = argv[1];
63. hostport = atoi(argv[2]);
64. if(hostport < 1024 || hostport >65535)
65. {
66. cerr << "Error: port=" << hostport
67. << " Error, range 1024 - 65535" << endl;
68. exit(0);
69. }
70. serversendContents = argv[3];
71. break;
72. default:
73. break;
74. }
75.}
76.
77.void clearfd(int fd,fd_set& rdfds)
78.{
79. FD_CLR(fd,&rdfds);
80. mapgroupsor it = groups.find(fd);
81. if(it != groups.end())
82. {
83. cerr << "client host=" << it->second.host << ", port=" << it->second.port
84. << " close" << endl;
85. groups.erase(fd);
86. }
87.}
88.
89.// recv and send message
90.void recvandsend(int fd,fd_set& rdfds,string& contents, const string& texts)
91.{
92. // 接受消息
93. char buffer[1024];
94. int rets=0;
95. int ret=0;
96. ret = recv(fd,buffer,8,0);
97.
98. if(ret == 0)
99. {
100. clearfd(fd,rdfds);
101. return;
102. }
103. if(ret == 8)
104. {
105. buffer[8]='\0';
106. int len = atoi(buffer);
107. if(len < 1024){
108. while((ret = recv(fd,buffer,len,0))>0)
109. {
110. contents.append(buffer,ret);
111. rets += ret;
112. len-=ret;
113. if(len==0)
114. break;
115. }
116. if(ret == 0){
117. clearfd(fd,rdfds);
118. return;
119. }
120. }else{
121. int buflen=1024;
122. while( (ret = recv(fd,buffer,buflen,0)) > 0)
123. {
124. contents.append(buffer,ret);
125. rets += ret;
126. len-=ret;
127. if(len<2048){
128. buflen=len;
129. }
130. if(len <= 0)
131. break;
132. }
133. if(ret == 0){
134. clearfd(fd,rdfds);
135. return;
136. }
137. }
138. }else{
139. clearfd(fd,rdfds);
140. return;
141. }
142.
143. // 發送信息
144. sprintf(buffer,"%8d",texts.length());
145. string sendContents = string(buffer,8);
146. sendContents += texts;
147.
148. const char* content = sendContents.c_str();
149. int send=0;
150. int length = sendContents.length();
151.
152. // send
153. while(1)
154. {
155. int ret = write(fd,content+send,length-send);
156. if(ret == 0)
157. {
158. // server close
159. cerr << "Error: server close" << endl;
160. clearfd(fd,rdfds);
161. return;
162. }
163. send += ret;
164. if(length == send)
165. break;
166. }
167.}
168.
169.int
170.main ( int argc, char *argv[] )
171.{
172. getCMD(argc,argv);
173.
174. int fd;
175. // create socket
176. if((fd=socket(PF_INET,SOCK_STREAM,0)) == -1)
177. {
178. cerr << "Error: socket()" <<endl;
179. exit(0);
180. }
181. //
182. struct hostent *he;
183. he = gethostbyname(hostname.c_str());
184. if(he == NULL ) {
185. cerr <<"Error: gethostbyname() error,hostname=" << hostname << endl;
186. exit(0);
187. }
188.
189. struct sockaddr_in serv_addr;
190.
191. serv_addr.sin_family=AF_INET;
192. serv_addr.sin_port=htons(hostport);
193. serv_addr.sin_addr=*((struct in_addr*)he->h_addr);
194. bzero( &(serv_addr.sin_zero),8);
195.
196. // bind
197. if(bind(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1) {
198. cerr<<"Error: bind() error"<<endl;
199. exit(0);
200. }
201.
202. // listen
203. int ret_listen = listen(fd,5);
204. if(ret_listen < 0)
205. {
206. cerr << "Error: Listen port error,socket fd: " << fd << endl;
207. cerr << "Error: listen errno = " << ret_listen << endl;
208. exit(0);
209. }
210.
211. fd_set rdfds;
212. int nfds;
213.
214. // First poll the sockets
215. FD_ZERO(&rdfds);
216. FD_SET(fd, &rdfds);
217. while(1)
218. {
219. if ((nfds = select(FD_SETSIZE, &rdfds, NULL, NULL, NULL)) < 0) {
220. if (errno != EINTR) {
221. cerr << "Error: select error" << endl;
222. exit(3);
223. }
224. }
225.
226. if(FD_ISSET(fd, &rdfds))
227. {
228. socklen_t len;
229. struct sockaddr_in client_addr;
230. len = sizeof(struct sockaddr);
231. int clientfd = accept(fd,(struct sockaddr *)&client_addr,&len);
232. if(clientfd == -1)
233. {
234. cerr << "Error: accept client error" << endl;
235. }else{
236. clientInfo info;
237. info.host = inet_ntoa(client_addr.sin_addr);
238. info.port = ntohs(client_addr.sin_port);
239. cerr << "server: got connection from "<< info.host
240. <<", port "<< info.port << endl;
241. groups.insert(make_pair(clientfd,info));
242. FD_SET(clientfd,&rdfds);
243. }
244. }else{
245. mapgroupscor it;
246. for(it = groups.begin(); it != groups.end(); ++it)
247. {
248. if(FD_ISSET(it->first,&rdfds))
249. {
250. string strRev;
251. recvandsend(it->first,rdfds,strRev,serversendContents);
252. break;
253. }
254. }
255. }
256.
257. }
258.
259. return 0;
260.} /* ---------- end of function main ---------- */
261.
上面的代碼在linux下已經編譯通過