热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

32通过tcp发送数组_客户端发送成功,服务器为什么收不到呢?

代码敲了这么多年,头疼的不是写代码,而是调试代码。自从进了培训行业,我又发现,最头疼的还不是自己调试代码,而是

    ffccede888c0b9d225b9766353a6e199.png

代码敲了这么多年,头疼的不是写代码,而是调试代码。自从进了培训行业,我又发现,最头疼的还不是自己调试代码,而是帮别人调试代码。经常有学生直接把整个工程打包发过来:老师,某某某个功能有问题,帮我看下...最常见的问题有:
  • 第一次运行可以,怎么第二次就不行了?

  • 代码昨晚还是好好的,怎么今天就不行了?

  • 我已经保存数据了呀,怎么还是查不到?

  • 客户端发送数据了呀,服务器怎么收不到呢?

  • 我就照着你的代码写的啊,怎么运行结果不对呢?

140b6c7c008eb3770e134438991da7ec.png

这些问题,很让人奔溃!不去调试代码,怎么知道呢?下面就来总结总结,我调试过的关于“客户端发送成功,服务器却收不到”的问题原因。

1 发送的字节数错误

client.c

#include #include /* See NOTES */#include #include #include #include #include #include #include int main(){ int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == sockfd) { perror("socket"); exit(1); } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = 8000; server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //向服务器发起连接 int ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (-1 == ret) { perror("connect"); exit(1); } char *buf = "helloworld"; //每隔 1S 向服务器发送一个字符串 while (1) {        ret = send(sockfd, buf, sizeof(buf), 0);  //问题代码 if (-1 == ret) { perror("send"); exit(1); } sleep(1); } close(sockfd); return 0;}

注:注意 37 行,sizeof(buf)

server.c

#include #include /* See NOTES */#include #include #include #include #include #include #include int main(){ //创建socket int sockfd = socket(AF_INET, SOCK_STREAM, 0); //ipv4协议 流式套接字 具体的协议类型 if (-1 == sockfd) { perror("socket"); exit(1); } int opt = 1; setsockopt(sockfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //地址可以被重复绑定 struct sockaddr_in server_addr; //保存服务器的信息 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = 8000; server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //127.0.0.1回环ip 表示本机 测试时候可以用 //绑定信息 int ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (-1 == ret) { perror("bind"); exit(1);    } //设置监听队列 ret = listen(sockfd, 10); if (-1 == ret) { perror("listen"); exit(1); } printf("等待客户端的连接...\n"); struct sockaddr_in client_addr; //用于保存客户端的信息 int length = sizeof(client_addr); //接受连接(建立TCP连接) int fd = accept(sockfd, (struct sockaddr *)&client_addr, &length); if (-1 == fd) { perror("accept"); exit(1); } printf("接受客户端的连接 %d\n", fd); char buf[32] = {0}; while (1) { //从fd接收消息,TCP连接相当于一个文件,fd就是文件描述符,从fd读取数据,就是从TCP连接接收数据 ret = recv(fd, buf, sizeof(buf), 0); if (-1 == ret) { perror("recv"); exit(1); } printf("%s\n", buf); memset(buf, 0, sizeof(buf)); } close(fd); close(sockfd); return 0;}运行代码,服务器端看到的现象是这样的:

7700f6b370725dff3fce0cfd2f962b77.png

客户端发送的是字符串 “helloworld”,服务器只收到了部分数据。这种情况,要么是客户端发送字节数错误,要么是服务器接收的字节数错误。最常见的就是代码中的写法。客户端代码,buf是一个指针,用 send 发送数据的时候,习惯性的写成了:

sizeof(buf) //只有四个字节所以发送的时候只把 “helloworld” 部分字节发送过去。

解决方法:

把客户端的发送的长度改成:

strlen(buf)

2 发送数据和接收数据的格式不一致

client.c

struct Message{ char sex; int id; char name[32];};typedef struct Message Message;int main(){ // .... Message mesg; //每隔 1S 向服务器发送一个字符串 while (1) { memset(&mesg, 0, sizeof(mesg)); mesg.sex = 'm'; mesg.id = 1; strcpy(mesg.name, "jack"); ret = send(sockfd, &mesg, sizeof(mesg), 0); if (-1 == ret) { perror("send"); exit(1); } sleep(1); } // ...}

注:注意结构体的成员。

server.c

struct Message{ int id; char name[32];};typedef struct Message Message;int main(){ // ... Message mesg; while (1) { ret = recv(fd, &mesg, sizeof(mesg), 0); if (-1 == ret) { perror("recv"); exit(1); } printf("id = %d name = %s\n", mesg.id, mesg.name); memset(&mesg, 0, sizeof(mesg)); } // .... return 0;}服务器端运行结果:

c74c6c5195ea66a89449e46f8f0cfc8a.png

很显然,服务器端收到的数据和客户端发送的数据不一致。因为客户端发送的结构体有三个成员,服务器接收数据的结构体只有两个成员,服务器收到字节流直接填入结构体,根本对应不上。

解决方法:

客户端和服务器结构体保持一致,或者使用相同的头文件。

3 发送的结构体包含指针

client.c

struct Message { char sex; int id; char *name; //指针 不是数组};typedef struct Message Message;int main(){ // .... Message mesg; mesg.sex = 'm'; mesg.id = 1; mesg.name = (char *)malloc(sizeof(char) * 32); strcpy(mesg.name, "jack"); //每隔 1S 向服务器发送一个字符串 while (1) { ret = send(sockfd, &mesg, sizeof(mesg), 0); if (-1 == ret) { perror("send"); exit(1); } sleep(1); }}

注:结构体成员有一个指针。

server.c

struct Message{ char sex; int id; char *name;};typedef struct Message Message;int main(){ Message mesg; while (1)    { ret = recv(fd, &mesg, sizeof(mesg), 0); if (-1 == ret) { perror("recv"); exit(1); } printf("sex = %c id = %d name = %s\n", mesg.sex, mesg.id, mesg.name); memset(&mesg, 0, sizeof(mesg)); }}服务器运行结果:

66cc87217fbdf551b3d4789ee3d91198.png

服务器端直接段错误死掉了。客户端发送的结构体有一个成员是指针,指向客户端进程的堆空间。客户端在发送数据的时候,直接把指针(即地址)发送过去,而指针指向的内容(即 jack)并没有发送过去。服务器收到的指针,在客户端进程里面是合法的指针,但是在服务器这就变成了野指针。

解决方法:

结构体里面的指针改成数组。

4 一次发送对应多个接收

client.c

int main(){ // .... char *buf = "helloworld"; //每隔 1S 向服务器发送一个字符串 while (1) { ret = send(sockfd, buf, strlen(buf), 0); if (-1 == ret) { perror("send"); exit(1); } sleep(1); }}

server.c

void *receive(void *arg){ int fd = *(int *)arg; int ret; char buf[32] = {0}; while (1) { ret = recv(fd, buf, sizeof(buf), 0); if (-1 == ret) { perror("recv"); } printf("收到客户端的消息:%s\n", buf); memset(buf, 0, sizeof(buf)); } }int main(){    // ....     pthread_t tid; ret = pthread_create(&tid, NULL, receive, &fd); if (-1 == ret) { perror("pthread_create"); exit(1); } char buf[32] = {0}; while (1)    { ret = recv(fd, buf, sizeof(buf), 0); if (-1 == ret) { perror("recv"); exit(1); }    } // ....}

注:主线程和子线程都有接收的函数。

运行结果,服务器收不到任何数据。原因也很简单,只不过把它放在工程里面可能不容易发现。服务器两个线程都在接收数据,所以不好判断哪个 recv 收到了数据。

解决办法:

确保服务器端同一时刻只有一个 recv 函数在接收数据。

5 接收数据存放位置错误

client.c

int main(){    char *buf = "helloworld"; //每隔 1S 向服务器发送一个字符串 while (1) { ret = send(sockfd, buf, strlen(buf), 0); if (-1 == ret) { perror("send"); exit(1); } sleep(1); }}

server.c

int main(){ // ....    char *buf = (char *)malloc(sizeof(char) * 128); while (1)     {    ret = recv(fd, &buf, 128, 0); if (-1 == ret) { perror("recv"); exit(1); } printf("%s\n", buf); }}

注:代码第 8 行,对指针 buf 再取地址。

服务器运行结果:

ae45a8e954b93e8bf1042c840d0a9b46.png

这个还是指针的使用问题。buf本来就是一个指针指向堆内存,程序的本意是把接收到的数据放在 buf 指向的内存空间,因为多了一个 & 符号,所以进程把收到的数据放在了指针 buf 四个字节中,很显然,一共接收 128 字节,越界访问。

解决办法:

recv 函数去掉 & 符号。以上五种情况是我见过最多的,其实问题一点也不难,主要是放在项目中很难被发现。还有哪些常见错误,欢迎公众号后台回复补充。

8bd2048f8566be083ee601ccf75ba007.png

PS.如果你还在为简历上没有合适的项目而发愁,如果你还不知道毕业设计该做什么,智能家居项目实战奉上!从零开始,3000行代码体验嵌入式开发完整流程。

58c60d2f52ba5f97736e9fc7dcda6150.png

04f301c586414091f4bbdba7b091a26a.png

65ca4710322dfe21ccfcbcdc4c013f45.png

1bad76083ea98601b6517beea52bd18f.png

b93fa68099eca3546561c9e1f9613530.png

a1f32ceb6b6b27caacd2a7e28a54365f.png

143c1de376c8ce4428b305b10f69bfbd.png




推荐阅读
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 20100423:Fixes:更新批处理,以兼容WIN7。第一次系统地玩QT,于是诞生了此预备式:【QT版本4.6.0&#x ... [详细]
  • 本文详细介绍了 GWT 中 PopupPanel 类的 onKeyDownPreview 方法,提供了多个代码示例及应用场景,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • CMake跨平台开发实践
    本文介绍如何使用CMake支持不同平台的代码编译。通过一个简单的示例,我们将展示如何编写CMakeLists.txt以适应Linux和Windows平台,并实现跨平台的函数调用。 ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
  • 本文探讨了 Objective-C 中的一些重要语法特性,包括 goto 语句、块(block)的使用、访问修饰符以及属性管理等。通过实例代码和详细解释,帮助开发者更好地理解和应用这些特性。 ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 本文详细介绍了Java中的输入输出(IO)流,包括其基本概念、分类及应用。IO流是用于在程序和外部资源之间传输数据的一套API。根据数据流动的方向,可以分为输入流(从外部流向程序)和输出流(从程序流向外部)。此外,还涵盖了字节流和字符流的区别及其具体实现。 ... [详细]
  • 不确定性|放入_华为机试题 HJ9提取不重复的整数
    不确定性|放入_华为机试题 HJ9提取不重复的整数 ... [详细]
  • 本文介绍了一种从与src同级的config目录中读取属性文件内容的方法。通过使用Java的Properties类和InputStream,可以轻松加载并获取指定键对应的值。 ... [详细]
  • 本文深入探讨了HTTP请求和响应对象的使用,详细介绍了如何通过响应对象向客户端发送数据、处理中文乱码问题以及常见的HTTP状态码。此外,还涵盖了文件下载、请求重定向、请求转发等高级功能。 ... [详细]
author-avatar
用户hxjr5k4y3f
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有