首页 > 解决方案 > C TCP write() 和 read() 来自 main 中定义的套接字

问题描述

信息

问题: 我正在尝试从同一个主函数设置 TCP 套接字read()write()但是我不确定如何正确地从套接字读取。

背景信息:我与单独的可执行文件进行通信,一个用于阅读(服务器),另一个用于写作(客户端)。

为此,我使用了这个网站作为指导。https://www.geeksforgeeks.org/tcp-server-client-implementation-in-c/

我从 Remy Lebeau 对C 套接字读取和写入的评论中了解到,返回的套接字accept()由服务器使用,而返回的套接字socket()由客户端使用。

我对套接字的写入工作正常。

Awaiting message from a client...
Address: 2, Port: 4547
Socket: 4
Serv addr: -1894572528
Size of server: 16
Message to send to server: hey
sendBytes: 3: hey
Recv bytes: 0
Recieved message: 

代码

该程序由三个功能组成

主要的()

createTcpRcvSock()

createTcpSendSock()

函数头及其主体

main(),包含和定义

#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <arpa/inet.h> 
#include <errno.h>
#include <string.h>

#define PORT 4547
int main(){

    int recvSock,sendSock,recvN,sendN,bufferSize,acceptSock,clilen;
    struct sockaddr_in cli_addr;

    char sendBuffer[256];
    char recvBuffer[256];

    recvSock = createTcpRecvSock();

    clilen = sizeof(cli_addr);

    acceptSock = accept(recvSock, (struct sockaddr *)&cli_addr, clilen);

    sendSock = createTcpSendSock();

    printf("Message to send to server: ");

    bzero(sendBuffer,256);
    scanf("%s",&sendBuffer);
    bufferSize = strlen(sendBuffer);
    sendN = write(sendSock,sendBuffer,bufferSize);
    printf("sendBytes: %d: %s\n",sendN,sendBuffer);
    if(sendN < 0){
        printf("Error writing to socket\n");
    }

    bzero(recvBuffer,256);
    bufferSize = strlen(recvBuffer);
    recvN = read(acceptSock,recvBuffer,bufferSize);
    printf("Recv bytes: %d\n", recvN);
    if(recvN < 0){
        printf("Error reading from socket\n");
    }
    printf("Recieved message: %s\n",recvBuffer);
}

createTcpSendSock()

int createTcpSendSock(){
    int sockfd;
    struct sockaddr_in serv_addr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0){
        error("ERROR opening socket");
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(PORT);

    printf("Socket: %d\n", sockfd);
    printf("Serv addr: %d\n", &serv_addr);
    printf("Size of server: %d\n", sizeof(serv_addr));
    
    if (connect(sockfd,(struct sockaddr *)&serv_addr ,sizeof(serv_addr)) < 0){ 
        printf("Error connecting: %d:  %s\n",errno,strerror(errno));
    }
    return sockfd;
} 

createTcpRecvSock()

int createTcpRecvSock(){

    int sockfd,portno,clilen,opt;
    struct sockaddr_in serv_addr;

    opt = 1;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        error("ERROR opening socket");
    }
    printf("Success opeing socket\n");

    bzero((char *) &serv_addr, sizeof(serv_addr));

    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))){
        printf("Setting socket options error: %d: %s\n",errno, strerror(errno));
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(PORT);

    printf("Awaiting message from a client...\n");
    printf("Address: %d, Port: %d\n", AF_INET, PORT);

    if(
    bind(sockfd,
    (struct sockaddr *) &serv_addr, 
    sizeof(serv_addr))
     < 0)
    {
        printf("Error on binding: %d, %s\n",errno, strerror(errno));
    }
    listen(sockfd,6);

    return sockfd;
}

预期的

我希望输出Received message: <User entered message>

实际的

但是即使没有循环,程序也会挂起:

Success opeing socket
Awaiting message from a client...
Address: 2, Port: 4547

任何帮助将不胜感激,我已尝试使其尽可能可读。

标签: clinuxsocketstcp

解决方案


当您以其他方式知道长度时,不要使用字符串函数。它会让你陷入困境。

bzero(recvBuffer,256);
bufferSize = strlen(recvBuffer);
recvN = read(acceptSock,recvBuffer,bufferSize);

您清空缓冲区,使其仅包含零。由于零字节标记字符串的结尾,因此strlen将返回零。因此,您尝试使用声称大小为零的缓冲区进行读取。

strlen功能永远不会告诉您有多少可用空间。它告诉你字符串数据有多大。如果那里没有字符串数据,那么调用strlen.

然后你这样做:

printf("Recieved message: %s\n",recvBuffer);

虽然它可能适用于您当前的代码方式,但这是一个不好的习惯。返回的read函数recvN,您收到的字节数。您忽略了这一点,并要求printf仅从数据中找出要打印的内容。不要这样做。最终会给你带来麻烦。用于recvN了解要打印的字节数。


推荐阅读