热门标签 | 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




推荐阅读
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社区 版权所有