编程语言
首页 > 编程语言> > TCP客户端程序

TCP客户端程序

作者:互联网

  TCP客户端程序的函数调用顺序为:socket -> connect -> send/recv

  socket、send和recv函数在TCP服务器程序中已经说过了,这里就不赘述了。

connect

  connect函数的原型为:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

  sockfd:socket函数返回的套接字描述符

  addr:需要连接的IP地址和端口号,但一般传入struct sockaddr_in类型的指针

   addrlen:传入sizeof(struct sockaddr_in)

  struct sockaddr_in结构定义如下:

struct sockaddr_in{
    sa_family_t     sin_family;   /* 地址族(Address Family)*/
    uint16_t        sin_port;     /* 端口号 */
    struct in_addr  sin_addr;     /* IP地址 */
    char            sin_zero[8];  /* 不使用,一般用0填充 */
};

  struct in_addr结构定义如下:

struct in_addr{
    in_addr_t  s_addr;  /* 32位的IP地址 */
};

  同样的,对于TCP客户端而言,sin_family的值为AF_INET,sin_addr.s_addr写入服务器的IP地址,用inet_addr函数转换,sin_port写入服务器的端口,用htons函数转换。

  connect函数成功返回0,失败返回-1。

  connect成功之后便可用recv和send函数收发数据了,同样的,如果服务器断开连接,那么recv函数将不再阻塞,返回值为0,可以通过recv的返回值判断服务器是否断开连接。

  不同的是调用recv和send时,TCP服务器程序传入的sockfd为accept返回的值,而TCP客户端程序传入的直接就是socket函数的返回值。

测试程序如下:

 1  /**
 2   * filename: tcp_client.c
 3   * author: Suzkfly
 4   * date: 2021-01-22
 5   * platform: Ubuntu
 6   * 配合windows的网络调试工具使用:
 7   *     1、先保证windows与Ubuntu在同一网段且互相能ping通;
 8   *     2、在windows下打开网络调试助手,选择协议类型为TCP Server,本地主机地址选
 9   *        择windows的IP地址(或者windows下能和Ubuntu ping通的地址),端口号和
10   *        本文件中传入的端口号一致,接收设置和发送设置都选择ASCLL。
11   *     3、点击“打开”按钮。
12   *     4、运行Ubuntu下的TCP客户端程序;
13   *     5、连接成功后在网络调试助手上发送数据,在Ubuntu下的终端上能看到,
14   *        在Ubuntu下的终端上输入字符串按回车发送,在windows上的网络调试助手上也
15   *        能看到。
16   */
17 #include <stdio.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <string.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 
24 #define IP_ADDR "192.168.0.1"  /* 服务器IP地址 */
25 #define PORT    24576          /* 服务器端口号 */
26 
27 
28 int main(int argc, const char *argv[])
29 {
30     int sock_fd = 0;
31     int ret = 0;
32     struct sockaddr_in serv_addr; /* 服务器地址 */
33     int pid = 0;
34     char buf[128] = { 0 };
35     int len = 0;
36     
37     /* 创建TCP套接字 */
38     sock_fd = socket(AF_INET, SOCK_STREAM, 0);
39     if (sock_fd < 0) {
40         printf("socket failed\n");
41         return 0;
42     }
43     
44     /* 与服务器建立连接 */
45     memset(&serv_addr, 0, sizeof(struct sockaddr_in));
46     serv_addr.sin_family = AF_INET;
47     serv_addr.sin_addr.s_addr = inet_addr(IP_ADDR);     /* 服务器IP */
48     serv_addr.sin_port = htons(PORT);                   /* 服务器端口号 */
49     ret = connect(sock_fd, 
50                   (struct sockaddr *)&serv_addr, 
51                   sizeof(struct sockaddr_in));
52     if (ret == 0) {
53         printf("connect ok\n");
54     } else {
55         printf("connect failed\n");
56         close(sock_fd);
57         return 0;
58     }
59     
60     pid = fork();
61     
62     if (pid > 0) {              /* 接收数据 */
63         while (1) {
64             memset(buf, 0, sizeof(buf));
65             len = recv(sock_fd, buf, sizeof(buf), 0);
66             
67             if (len == 0) {     /* 如果recv返回0,则表示远端断开连接 */
68                 break;
69             }
70             
71             printf("len = %d\n", len);
72             printf("data: %s\n", buf);
73         }
74     } else if (pid == 0) {      /* 发送数据 */
75         while (1) {
76             memset(buf, 0, sizeof(buf));
77             scanf("%s", buf);
78             send(sock_fd, buf, strlen(buf), 0);
79         }
80     }
81 }

  该程序在服务器断开连接的情况下,客户端不进行重连,而是直接退出程序。

  该程序存在一个bug,就是发送数据和接收数据是通过不同的进程来控制的,而当服务器断开连接后,接收进程结束了,但发送进程还未结束。

网络调试助手设置如下:

 

 

标签:struct,TCP,connect,客户端程序,buf,sin,addr
来源: https://www.cnblogs.com/Suzkfly/p/14315101.html