首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

3.3  TCP客户端与服务器

TCPTCP/IP协议簇中最常用的协议,这一节将通过两个示例说明怎样创建TCP的客户端和服务器。

3-1说明了怎样创建、建立和终止到远程TCP端口的连接。

3-1 TCP的客户端(client1.c)

1   /*

2    * client1.c

3    *

4    * Establish TCP client connection &

5    * terminate connection using socket(),

6    * connect() and close() functions.

7    *

8    *

9    *

10   */

11

12 #include <stdio.h>

13 #include <sys/types.h>

14 #include <sys/socket.h>

15 #include <netinet/in.h>

16

17 int

18 main (int argc, char *argv[])

19 {

20         struct sockaddr_in sin;

21         int sock = 0;

22         int ret = 0;

23

24        if(argc != 3)

25         {

26              printf("usage: %s: ip_address port\n", argv[0]);

27              return(1);

28         }

29

30         sock = socket(AF_INET, SOCK_STREAM, 0);

31         if(sock < 0)

32         {

33              printf("TCP client socket() failed.\n");

34              return(1);

35         }

36

37         memset(&sin, 0x0, sizeof(struct sockaddr_in *));

38

39         sin.sin_family = AF_INET;

40         sin.sin_port = htons(atoi(argv[2]));

41         sin.sin_addr.s_addr = inet_addr(argv[1]);

42

43         ret = connect(sock, struct sockaddr *)&sin,

44                          sizeof(struct sockaddr);

45         if(ret < 0)

46         {

47                 printf("TCP client connect() failed.\n");

48                 close (sock);

49                 return(1);

50         }

51

52         printf("TCP client connected.\n");

53         close(sock);

54

55         printf("TCP client connection closed.\n");

56

57         return(0);

58 }

编译

(foster@syngress ~/book) $ gcc -o client1 client1.c

(foster@syngress ~/book) $ ./client1

usage: ./client1: ip_address port

执行

(foster@syngress ~/book) $ ./client1 127.0.0.1 80

TCP client connected.

TCP client connection closed.

(foster@syngress ~/book) $ ./client1 127.0.0.1 81

TCP client connect() failed.

程序client1.c要求两个命令行参数:目标IP地址和端口。这个程序分配了一个套接字标识符并且连接到了指定的IP地址及端口,但没有传送数据,然后关闭套接字。如果不能建立到指定IP地址和端口的连接,将打印出错信息并退出。

分析

       30行,程序通过调用socket( )函数分配了一个套接字标识符,将AF_INET作为域参数传送,表示该套接字使用IP协议;将SOCK_STREAM作为类型参数传送type,表示该套接字在传输层使用TCP协议;将0传给形参protocol作为协议值,因为这个参数通常不用作TCP连接。

       37行,对sockaddr_in结构进行初始化,用来定义套接字将要连接的远程端点。

       39行,远程端点的family域被指定为AF_INET,与第28行中传给socket( )函数的域参数一致。

       40行,指定要连接的远程端口。端口号由命令行参数给出,并以字符数组(char *)的形式传递进来,然后通过atoi( )函数转换为一个4字节的整数(int),再转换为网络字节顺序的2字节短整型数,将最后得到的值赋给sockaddr_in结构的sin_port成员。

       41行,远程IP地址由命令参数指定并以字符数组(char *)的形式传递进来,然后该字符串被转换成对应的32位无符号整数,并赋值给sockaddr_in结构的sin_ addr.s_addr成员。函数inet_addr( )用于将字符数组转换为32位无符号值的形式。

       43行到第44行,套接字与远程主机及端口建立连接,此处将发生TCP连接的“三次握手”。

       53行,关闭套接字并终止连接。

3-2说明了怎样创建TCP服务器端套接字。服务器端套接字作为一个TCP客户端能够连接的端点。

3-2 TCP服务器(server1. c)

1   /*

2    * server1.c

3    *

4    * Create TCP server socket, accept

5    * one TCP client connection using

6    * socket(), bind(), listen() and

7    * accept().

8    *

9    * foster <jamescfoster@gmail.com>

10   */

11

12 #include <stdio.h>

13 #include <sys/types.h>

14 #include <sys/socket.h>

15 #include <netinet/in.h>

16

17 int

18 main (int argc, char *argv[])

19 {

20        struct sockaddr_in sin ;

21        struct sockaddr_in csin;

22        socklen_t len = sizeof(struct sockaddr);

23        short port = 0;

24        int    csock = 0;

25        int    sock = 0;

26        int    ret = 0;

27

28        if(argc != 2)

29        {

30                 printf("usage: %s: port\n", argv[0]);

31                 return(1);

32        }

33

34        port = atoi(argv[1]);

35

36        sock = socket(AF_INET, SOCK_STREAM, 0);

37        if(sock < 0)

38        {

39                printf("TCP server socket() failed.\n");

40                return(1);

41        }

42

43        memset(&sin, 0x0, sizeof(struct sockaddr_in *));

44

45        sin.sin_family       = AF_INET;

46        sin.sin_port         = htons(port);

47        sin.sin_addr.s_addr = INADDR_ANY;

48

49        ret = bind(sock, (struct sockaddr *)&sin,

50                             (struct sockaddr));

51        if(ret < 0)

52        {

53                printf("TCP server bind() failed.\n");

54                close (sock);

55                return(1 );

56        }

57

58        ret = listen(sock, 5);

59        if(ret < 0)

60        {

61                printf("TCP server listen() failed.\n");

62                close (sock);

63                return(1 );

64        }

65

66        printf("TCP server listening.\n");

67

68        memset(&csin, 0x0, sizeof(struct sockaddr));

69

70        csock = accept(sock, (struct sockaddr *)&csin, &len);

71        if(csock < 0)

72        {

73                printf("TCP server accept() failed.\n");

74        }

75        else

76        {

77                printf("TCP server: TCP client connection " \

78                "on port %d.\n", port);

79                close(csock);

80        }

81

82        close(sock);

83

84        return(0);

85 }

编译

(foster@syngress ~/book) $ gcc -o server1 server1.c

(foster@syngress ~/book) $ ./server1

usage: ./server1: port

执行

(foster@syngress ~/book) $ ./server1 4001

TCP server listening.

server1.c是一个简单的TCP服务器程序,它只带有一个命令行参数表示端口号,服务器将在这个端口上监听远程客户端的连接。程序首先调用socket( )函数分配一个套接字标识符,然后绑定到指定的端口并调用accept( )函数进行监听,这个函数将等待客户端的连接。收到客户端的连接以后,与TCP客户端的连接以及服务器端套接字被关闭,程序终止。

分析

       36行,程序调用socket( )函数分配套接字标识符,将AF_INET作为域参数传递,表示该套接字使用IP协议;将SOCK_STREAM作为类参数传递,表示该套接字在传输层使用TCP协议进行通信;将0传递给作为协议参数传递,因为在分配TCP套接字的时候,通常不会用到这个参数。

       43行,初始化sockaddr_in结构,用来定义套接字将要绑定的本地端点。

       45行,本地端点的family域被指定为AF_INET,与第36行传给socket( )函数的参数一致。

       46行,指定将要绑定的本地端口,端口号由命令行参数给出并作为字符数组(char *)传递进来。端口号通过atoi( )函数被转换成4字节的整型数,然后再转换为网络字节顺序的2字节短整型数,最后赋值给sockaddr_in结构的sin_port成员。

       47行,指定要绑定的本地IP地址。这里用到了无符号整型常量INADDR_ANY,这个值表示套接字将会绑定到所有可用的网络接口,包括回送接口(loopback interface)INADDR_ANY相反,在主机有多个网络接口的情况下,如果用指定网络接口的IP地址代替INADDR_ANY,则可以将套接字绑定到其中的一个接口。

       49行,调用bind( )函数指定本地端点的信息,包括本地IP地址、端口以及套接字描述符。

       58行,调用listen( )函数,指定在拒绝新连接以前,可排除等待的TCP客户端连接请求的数目,并且指定套接字已经就绪,可以接收客户端的连接。程序从这里开始处理客户端的连接。

       70行,调用accept( )函数接收TCP客户端的连接请求,accept( )函数被调用时,将会等待(阻塞)客户端的连接。当收到一个新的TCP客户端请求以后,accept( )函数将返回一个套接字描述符来代表这个新的连接。

       79行,关闭由accept( )函数返回的合法套接字描述符。

       82行,关闭服务器端套接字,不再允许客户端的连接。

3-3首先执行程序server1,接着再执行程序client1server1将分配一个套接字描述符,并绑定到命令行指定的端口,然后监听来自客户端的TCP连接。当执行client1时,将会在server1client1两个程序之间建立一个TCP连接。最后,两个程序都将关闭连接并终止。

3-3  TCP客户端与服务器的活动

1(foster@syngress ~/book) $ ./server1 4001 &

2./server1 4001 & [1] 31802

3

4(foster@syngress ~/book) $ ./client1 127.0.0.1 4001

5 ./client1 127.0.0.1 4001

6

7 TCP server: TCP client connection on port 4001.

8

9 TCP client connected.

10

11 [1]    Done        ./server1 4001

分析

server1执行时指令绑定4001TCP端口,并在该端口进行监听。在大部分操作系统上,11024号端口限制为仅供具有特定权限的程序使用,所以在这个示例里面使用了大于1024的端口。命令行末尾的&符号表示程序将作为后台进程运行,所以会立即返回到命令提示符以便执行client1程序。

       1行,TCSH shell打印出用户输入的命令。

       2行,TCSH shell打印server1后台进程的进程ID

       4行,以IP地址127.0.0.1和端口4001作为参数执行程序client1127.0.0.1是一个回送地址,被分配给回送接口。回送接口是一个仅能被本地主机上运行的程序所访问的逻辑接口。实际上大部分系统都将localhost作为127.0.0.1的别名。

       5行,TCSH shell打印用户输入的命令。

       7行,server1打印一条信息,表示它收到客户端的TCP连接,即client1发起的连接。

       9行,client1打印信息表明已经建立了到server1的连接。

上面介绍了TCPUDP套接字编程的基本知识,下面将转向UDP套接字的编程。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论