c - 当程序之前运行良好时,C 中的 TCP 分段错误(核心转储)
问题描述
我从 GeeksForGeeks 复制了代码,以便开始制作 TCP 程序。在我运行它几次之后它工作得很好......然后它突然没有......
服务器:
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
void func(int sockfd);
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 1)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client...\n");
// Function for chatting between client and server
func(connfd);
// After chatting close the socket
close(sockfd);
}
void func(int sockfd)
{
char buff[MAX];
int n;
for(;;)
{
bzero(buff, sizeof(buff));
n=0;
read(sockfd, buff, sizeof(buff));
printf("%s", buff);
}
}
客户:
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
void func(int sockfd);
int main()
{
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(PORT);
// connect the client socket to server socket
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
printf("connection with the server failed...\n");
exit(0);
}
else
{
printf("connected to the server..\n");
}
printf("boop");
// function for chat
func(sockfd);
// close the socket
close(sockfd);
}
void func(int sockfd)
{
printf("Heelloo");
char buff[MAX];
int n;
for(;;)
{
bzero(buff, sizeof(buff));
n=0;
printf("To client: ");
while((buff[n++] = getchar()) != '\n');
write(sockfd, buff, sizeof(buff));
}
}
该函数不完整,但问题似乎就在客户端 main() 中的 func() 调用之前。任何帮助,将不胜感激!
解决方案
write(sockfd, buff, sizeof(buff));
每本教如何正确使用套接字的教科书都会解释说,你绝对不能保证,无论如何,它write()
会实际将请求的字节数写入套接字。from 的返回值write()
表示实际写入的字节数(可能小于其第三个参数请求的字节数),写入套接字的代码必须正确实现必要的逻辑才能继续将剩余数据写入插座,如果需要的话。
此外,这里没有初始化整个buff
,只有它的初始部分,所以这会尝试编写整个buff
,这在技术上是未定义的行为。
read(sockfd, buff, sizeof(buff));
我解释的同样的事情write()
也适用于read()
。您必须检查 from 的返回值read()
以确定实际从套接字读取了多少。完全有可能read()
最终只读取第一个字符。其余部分buff
未初始化,并且包含随机垃圾,并且以下printf
搜索正确'\0'
终止的字符串注定要彻底失败,并崩溃。
每次运行程序时,由于各种原因,客户端和服务器都可能最终从套接字读取和写入不同数量的字节。这解释了为什么您观察到该程序随机失败,并且看似有效,但没有可预测的模式。
一般来说,像 GeeksForGeeks 这样的网站并不是用来学习编程的。他们缺乏适当的教程、技术信息和说明材料。正如我在开头提到的,学习网络编程和其他技术主题的最佳方式是通过有指导的、基于教科书的学习课程。你能在 GeeksForGeeks 上找到任何东西,你从哪里复制了这个程序,解释说你必须read
检查和的返回值write
吗?不,因为它不打算用作学习材料,但每个网络编程教程都必须解释不仅这一点,还要解释其他几个基本的相关概念。
推荐阅读
- node.js - SyntaxError: Unexpected token 'extends' Node.js VSCode Pug
- python - 在 GEKKO 中执行动态模拟时出错
- sql - postgresSql 查询修正
- android - Android 测试无法识别 Android 类
- php - 我需要关于我的 PDO 登录功能的反馈,会有错误吗?结构如何?
- c# - 模型绑定来自 Razor 页面发布表单上的路由参数
- oracle - Apex Oracle 如何创建有条件的强制列
- argocd - 如何使用带有 --revision 标志的 argocd app diff?
- java - Cucumber Maven 重新运行,运行所有场景而不是失败的场景
- python - Python Cumsum。使用 Pandas GroupBY 或 Transform 处理的任何简单方法?