2007年6月14日木曜日

TCP的socket连接示例

Made In Zeal 转载请保留原始链接:http://www.zeali.net/entry/13
标签 ( Tags ): socket , tcp , timeout , 超时 , 异步 , ioctl , 源代码
用C实现的TCP socket连接/读/写操作。采用fcntl设置非阻塞式连接以实现connect超时处理;采用select方法来设置socket读写超时。此示例可被编译运行于Windows/unix系统。

源文件connector.c

原来的代码在windows下编译不通过,今天qzj问起才发现。因为加了异步的处理,没有对这部分代码进行兼容性处理。本着做学问一丝不苟嘀精神,重新修改了一下源代码。以下代码在VC++6和linux下编译执行通过 :)

view plainprint?

1. /*
2.
3. * on Unix:
4.
5. * cc -c connector.c
6.
7. * cc -o connector connector.o
8.
9. *
10.
11. * on Windows NT:
12.
13. * open connector.c in Visual Studio
14.
15. * press 'F7' to link -- a project to be created
16.
17. * add wsock32.lib to the link section under project setting
18.
19. * press 'F7' again
20.
21. *
22.
23. * running:
24.
25. * type 'connector' for usage
26.
27. */
28.
29.
30. #include
31.
32. #include
33.
34. #include
35.
36. #include
37.
38. #include
39.
40. #include
41.
42. #ifdef WIN32
43.
44. #include
45.
46. #else
47.
48. #include
49.
50. #include
51.
52. #include
53.
54. #include
55.
56. #include
57.
58. #include
59.
60. #include
61.
62. #endif
63.
64.
65. #ifndef INADDR_NONE
66.
67. #define INADDR_NONE 0xffffffff
68.
69. #endif
70.
71. #define MAX_STRING_LEN 1024
72.
73. #define BUFSIZE 2048
74.
75.
76. #ifndef WIN32
77.
78. #define SOCKET int
79.
80. #else
81.
82. #define errno WSAGetLastError()
83.
84. #define close(a) closesocket(a)
85.
86. #define write(a, b, c) send(a, b, c, 0)
87.
88. #define read(a, b, c) recv(a, b, c, 0)
89.
90. #endif
91.
92.
93. char buf[BUFSIZE];
94.
95.
96. static char i_host[MAX_STRING_LEN]; /* site name */
97.
98. static char i_port[MAX_STRING_LEN]; /* port number */
99.
100.
101. void err_doit(int errnoflag, const char *fmt, va_list ap);
102.
103. void err_quit(const char *fmt, ...);
104.
105. int tcp_connect(const char *host, const unsigned short port);
106.
107. void print_usage();
108.
109.
110. //xnet_select x defines
111.
112. #define READ_STATUS 0
113.
114. #define WRITE_STATUS 1
115.
116. #define EXCPT_STATUS 2
117.
118.
119. /*
120.
121. s - SOCKET
122.
123. sec - timeout seconds
124.
125. usec - timeout microseconds
126.
127. x - select status
128.
129. */
130.
131. SOCKET xnet_select(SOCKET s, int sec, int usec, short x)
132.
133. {
134.
135. int st = errno;
136.
137. struct timeval to;
138.
139. fd_set fs;
140.
141. to.tv_sec = sec;
142.
143. to.tv_usec = usec;
144.
145. FD_ZERO(&fs);
146.
147. FD_SET(s, &fs);
148.
149. switch(x){
150.
151. case READ_STATUS:
152.
153. st = select(s+1, &fs, 0, 0, &to);
154.
155. break;
156.
157. case WRITE_STATUS:
158.
159. st = select(s+1, 0, &fs, 0, &to);
160.
161. break;
162.
163. case EXCPT_STATUS:
164.
165. st = select(s+1, 0, 0, &fs, &to);
166.
167. break;
168.
169. }
170.
171. return(st);
172.
173. }
174.
175.
176. int tcp_connect(const char *host, const unsigned short port)
177.
178. {
179.
180. unsigned long non_blocking = 1;
181.
182. unsigned long blocking = 0;
183.
184. int ret = 0;
185.
186. char * transport = "tcp";
187.
188. struct hostent *phe; /* pointer to host information entry */
189.
190. struct protoent *ppe; /* pointer to protocol information entry*/
191.
192. struct sockaddr_in sin; /* an Internet endpoint address */
193.
194. SOCKET s; /* socket descriptor and socket type */
195.
196. int error;
197.
198.
199. #ifdef WIN32
200.
201. {
202.
203. WORD wVersionRequested;
204.
205. WSADATA wsaData;
206.
207. int err;
208.
209.
210.
211. wVersionRequested = MAKEWORD( 2, 0 );
212.
213.
214.
215. err = WSAStartup( wVersionRequested, &wsaData );
216.
217. if ( err != 0 ) {
218.
219. /* Tell the user that we couldn't find a usable */
220.
221. /* WinSock DLL. */
222.
223. printf("can't initialize socket library\n");
224.
225. exit(0);
226.
227. }
228.
229. }
230.
231. #endif
232.
233.
234.
235. memset(&sin, 0, sizeof(sin));
236.
237. sin.sin_family = AF_INET;
238.
239.
240.
241. if ((sin.sin_port = htons(port)) == 0)
242.
243. err_quit("invalid port \"%d\"\n", port);
244.
245.
246.
247. /* Map host name to IP address, allowing for dotted decimal */
248.
249. if ( phe = gethostbyname(host) )
250.
251. memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
252.
253. else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )
254.
255. err_quit("can't get \"%s\" host entry\n", host);
256.
257.
258.
259. /* Map transport protocol name to protocol number */
260.
261. if ( (ppe = getprotobyname(transport)) == 0)
262.
263. err_quit("can't get \"%s\" protocol entry\n", transport);
264.
265.
266.
267. /* Allocate a socket */
268.
269. s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);
270.
271. if (s < 0)
272.
273. err_quit("can't create socket: %s\n", strerror(errno));
274.
275.
276.
277. /* Connect the socket with timeout */
278.
279. #ifdef WIN32
280.
281. ioctlsocket(s,FIONBIO,&non_blocking);
282.
283. #else
284.
285. ioctl(s,FIONBIO,&non_blocking);
286.
287. #endif
288.
289. //fcntl(s,F_SETFL, O_NONBLOCK);
290.
291. if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1){
292.
293. struct timeval tv;
294.
295. fd_set writefds;
296.
297. // 设置连接超时时间
298.
299. tv.tv_sec = 10; // 秒数
300.
301. tv.tv_usec = 0; // 毫秒
302.
303. FD_ZERO(&writefds);
304.
305. FD_SET(s, &writefds);
306.
307. if(select(s+1,NULL,&writefds,NULL,&tv) != 0){
308.
309. if(FD_ISSET(s,&writefds)){
310.
311. int len=sizeof(error);
312.
313. //下面的一句一定要,主要针对防火墙
314.
315. if(getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&error, &len) < 0)
316.
317. goto error_ret;
318.
319. if(error != 0)
320.
321. goto error_ret;
322.
323. }
324.
325. else
326.
327. goto error_ret; //timeout or error happen
328.
329. }
330.
331. else goto error_ret; ;
332.
333.
334. #ifdef WIN32
335.
336. ioctlsocket(s,FIONBIO,&blocking);
337.
338. #else
339.
340. ioctl(s,FIONBIO,&blocking);
341.
342. #endif
343.
344.
345. }
346.
347. else{
348.
349. error_ret:
350.
351. close(s);
352.
353. err_quit("can't connect to %s:%d\n", host, port);
354.
355. }
356.
357. return s;
358.
359. }
360.
361.
362. void err_doit(int errnoflag, const char *fmt, va_list ap)
363.
364. {
365.
366. int errno_save;
367.
368. char buf[MAX_STRING_LEN];
369.
370.
371. errno_save = errno;
372.
373. vsprintf(buf, fmt, ap);
374.
375. if (errnoflag)
376.
377. sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
378.
379. strcat(buf, "\n");
380.
381. fflush(stdout);
382.
383. fputs(buf, stderr);
384.
385. fflush(NULL);
386.
387. return;
388.
389. }
390.
391.
392. /* Print a message and terminate. */
393.
394. void err_quit(const char *fmt, ...)
395.
396. {
397.
398. va_list ap;
399.
400. va_start(ap, fmt);
401.
402. err_doit(0, fmt, ap);
403.
404. va_end(ap);
405.
406. exit(1);
407.
408. }
409.
410.
411. #ifdef WIN32
412.
413. char *optarg;
414.
415.
416. char getopt(int c, char *v[], char *opts)
417.
418. {
419.
420. static int now = 1;
421.
422. char *p;
423.
424.
425. if (now >= c) return EOF;
426.
427.
428. if (v[now][0] == '-' && (p = strchr(opts, v[now][1]))) {
429.
430. optarg = v[now+1];
431.
432. now +=2;
433.
434. return *p;
435.
436. }
437.
438.
439. return EOF;
440.
441. }
442.
443.
444. #else
445.
446. extern char *optarg;
447.
448. #endif
449.
450.
451. #define required(a) if (!a) { return -1; }
452.
453.
454. int init(int argc, char *argv[])
455.
456. {
457.
458. char c;
459.
460. //int i,optlen;
461.
462. //int slashcnt;
463.
464.
465. i_host[0] = '\0';
466.
467. i_port[0] = '\0';
468.
469.
470. while ((c = getopt(argc, argv, "h:p:?")) != EOF) {
471.
472. if (c == '?')
473.
474. return -1;
475.
476. switch (c) {
477.
478. case 'h':
479.
480. required(optarg);
481.
482. strcpy(i_host, optarg);
483.
484. break;
485.
486. case 'p':
487.
488. required(optarg);
489.
490. strcpy(i_port, optarg);
491.
492. break;
493.
494. default:
495.
496. return -1;
497.
498. }
499.
500. }
501.
502.
503. /*
504.
505. * there is no default value for hostname, port number,
506.
507. * password or uri
508.
509. */
510.
511. if (i_host[0] == '\0' || i_port[0] == '\0')
512.
513. return -1;
514.
515.
516. return 1;
517.
518. }
519.
520.
521. void print_usage()
522.
523. {
524.
525. char *usage[] =
526.
527. {
528.
529. "Usage:",
530.
531. " -h host name",
532.
533. " -p port",
534.
535. "example:",
536.
537. " -h 127.0.0.1 -p 4001",
538.
539. };
540.
541. int i;
542.
543.
544. for (i = 0; i < sizeof(usage) / sizeof(char*); i++)
545.
546. printf("%s\n", usage[i]);
547.
548.
549.
550. return;
551.
552. }
553.
554.
555. int main(int argc, char *argv[])
556.
557. {
558.
559. SOCKET fd;
560.
561. int n;
562.
563.
564. /* parse command line etc ... */
565.
566. if (init(argc, argv) < 0) {
567.
568. print_usage();
569.
570. exit(1);
571.
572. }
573.
574.
575. buf[0] = '\0';
576.
577.
578. /* pack the info into the buffer */
579.
580. strcpy(buf, "HelloWorld");
581.
582.
583. /* make connection to the server */
584.
585. fd = tcp_connect(i_host, (unsigned short)atoi(i_port));
586.
587.
588. if(xnet_select(fd, 0, 500, WRITE_STATUS)>0){
589.
590. /* send off the message */
591.
592. write(fd, buf, strlen(buf));
593.
594. }
595.
596. else{
597.
598. err_quit("Socket I/O Write Timeout %s:%s\n", i_host, i_port);
599.
600. }
601.
602.
603. if(xnet_select(fd, 3, 0, READ_STATUS)>0){
604.
605. /* display the server response */
606.
607. printf("Server response:\n");
608.
609. n = read(fd, buf, BUFSIZE);
610.
611. buf[n] = '\0';
612.
613. printf("%s\n", buf);
614.
615. }
616.
617. else{
618.
619. err_quit("Socket I/O Read Timeout %s:%s\n", i_host, i_port);
620.
621. }
622.
623. close(fd);
624.
625.
626. #ifdef WIN32
627.
628. WSACleanup();
629.
630. #endif
631.
632.
633. return 0;
634.
635. }

1 件のコメント:

匿名 さんのコメント...

GfypohVkyynmRbgswt ZfxbanIymentAizhjf DkrdcuDpyontDmqegiXimrdrBxvcrk EfdlmpZxmqlvJkhyrc TuzcxmRvxnct [url=http://www.megafucktube.co/redtube-sexy-videos/93327.html]Pigtail Brunette Whore gives Her Man Tug & Suck[/url] PpbqadVcoeiwMwuqun RgdptqIuoswo OxvcznQlnoteRnursr HmgyeiVtgwfwHsbqmv OasfwxKjjkyc http://www.megafucktube.co/redtube-sexy-videos/69814.html Liberty Shows off Hefty Chocolate Tits IgjjpiFafbrfTuphvp IlwahtEbploo QydnywJvexog GoarwqQjgvxjGypfguZamfkdKoqezi NcbsnxBiclou XtkwbqCqfbdu POV Bang With Hot Babe With Huge Butt jdvpamiabvim buivpcvjf cwtizomimlvynkt bbeybhwgx vxzexb