标签:struct TCP connect 客户端程序 buf sin addr
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
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。