Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何正确地从套接字读取数据?_C_Sockets - Fatal编程技术网

C 如何正确地从套接字读取数据?

C 如何正确地从套接字读取数据?,c,sockets,C,Sockets,我有一个简单的客户机/服务器应用程序。用户在控制台中写入字符串。当他按下回车键时,字符串被发送。我可以正确地传输一行,但在它将第一个发送的单词的第一个字母替换到下一行之后。例如,如果用户发送“Hello”,服务器将获得“Hello”,但之后,如果我再次发送“Hello”,服务器将获得“HHello”。如果我尝试在发送后清除客户端的缓冲区,它将不再发送任何内容 服务器代码: // Server side C/C++ program to demonstrate Socket programming

我有一个简单的客户机/服务器应用程序。用户在控制台中写入字符串。当他按下回车键时,字符串被发送。我可以正确地传输一行,但在它将第一个发送的单词的第一个字母替换到下一行之后。例如,如果用户发送“Hello”,服务器将获得“Hello”,但之后,如果我再次发送“Hello”,服务器将获得“HHello”。如果我尝试在发送后清除客户端的缓冲区,它将不再发送任何内容

服务器代码:

// Server side C/C++ program to demonstrate Socket programming 
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>

#define PORT 57174
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);

if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
    perror("socket failed");
    exit(EXIT_FAILURE);
}


if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
               &opt, sizeof(opt)))
{
    perror("setsockopt");
    exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );


if (bind(server_fd, (struct sockaddr *)&address,
         sizeof(address))<0)
{
    perror("bind failed");
    exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
    perror("listen");
    exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
                         (socklen_t*)&addrlen))<0)
{
    perror("accept");
    exit(EXIT_FAILURE);
}

char buffer[1024];
bzero(buffer, sizeof(buffer));
int step = 0;
   while(1){
   valread = read( new_socket , buffer, 1024);


   if(valread == 0)
       break;

   printf("%s", buffer );
printf("\n");

   bzero(buffer, sizeof(buffer));   


};

       return 0;
   } 
//用于演示套接字编程的服务器端C/C++程序
#包括
#包括
#包括
#包括
#包括
#包括
#定义端口57174
int main(int argc,char const*argv[]
{
int server_fd,新的_套接字,valread;
地址中的结构sockaddr_;
int opt=1;
int addrlen=sizeof(地址);
if((服务器fd=socket(AF\u INET,SOCK\u STREAM,0))==0)
{
perror(“套接字失败”);
退出(退出失败);
}
if(setsockopt)(服务器fd、SOL_套接字、SO_REUSEADDR | SO_REUSEPORT、,
&opt,sizeof(opt)))
{
perror(“setsockopt”);
退出(退出失败);
}
address.sin_family=AF_INET;
address.sin_addr.s_addr=INADDR\u ANY;
address.sin_port=htons(port);
if(bind(server_fd,(struct sockaddr*)和address,
sizeof(地址))
如果用户发送“Hello”,服务器将收到“Hello”,但在之后,如果我再次发送“Hello”,服务器将收到“HHello”

这是因为你错过了你的客户中的另一个

你需要更换

否则,在发送缓冲区并将i设置为0后,您将递增它,并在索引1处记住下一个字符,索引0处的字符仍然存在,您将一次又一次地发送它


您的客户在以下方面也有问题:

因为您没有在strlen返回期望值所需的buff中放置null字符,所以行为是未定义的

假设您不想发送\n


在服务器端

您使用空字符填充每个时间缓冲区,但如果您读取1024个字符,则缓冲区中没有空字符,printf将以未定义的行为退出缓冲区

警告读取错误时返回-1,valread==0错误

删除所有的bzero和just do

 char buffer[1024];
 ...
 while ((valread = read(new_socket, buffer, sizeof(buffer)-1)) > 0) {
   buffer[valread ] = 0;
   printf("%s", buffer);
 }
注意,我使用了sizeof(buffer)而不是1024,这样即使调整了缓冲区的大小,也可以确保大小正确


客户的其他意见:

  • 变量hello是无用的

  • 根据定义,sizeof(char)的值为1,因此sizeof(char)*N可以处处替换为N

  • 不要将读取字符与文本10和27进行比较,请与“\n”和“\e”进行比较

  • 您不需要在输入中管理EOF,因此您需要将读取的字符保存为int而不是char(如buf[i]is),以将其与EOF进行比较

在服务器中,变量步骤是无用的


因此,您使用SOCK_STREAM,因此您的套接字是一个流(tcp而非udp),这意味着您不能假设每次调用read时读取的数据的大小,我的意思是,如果客户端发送了N个字节,这并不意味着服务器将在相应的读取中读取N个字节(如果我可以说“对应”,因为没有对应;-)

假设其他问题已解决,如果您输入azeqsd,则发送azeqsd,但可能在服务器端,您将读取azeq,因此打印azeq\n,在下一个循环中,您将读取sd并打印sd\n

服务器也可能读取客户端单独发送的几个缓冲区的部分或全部串联

您想要这种行为吗?如果不需要,您需要在每个缓冲区之前发送大小,以知道即使在几次上读取多少数据,也可以构成完整的发送缓冲区(另一个优点是您不需要读取每个字节)

如果用户发送“Hello”,服务器将收到“Hello”,但在之后,如果我再次发送“Hello”,服务器将收到“HHello”

这是因为你错过了你的客户中的另一个

你需要更换

否则,在发送缓冲区并将i设置为0后,您将递增它,并在索引1处记住下一个字符,索引0处的字符仍然存在,您将一次又一次地发送它


您的客户在以下方面也有问题:

因为您没有在strlen返回期望值所需的buff中放置null字符,所以行为是未定义的

假设您不想发送\n


在服务器端

您使用空字符填充每个时间缓冲区,但如果您读取1024个字符,则缓冲区中没有空字符,printf将以未定义的行为退出缓冲区

警告读取错误时返回-1,valread==0错误

删除所有的bzero和just do

 char buffer[1024];
 ...
 while ((valread = read(new_socket, buffer, sizeof(buffer)-1)) > 0) {
   buffer[valread ] = 0;
   printf("%s", buffer);
 }
注意,我使用了sizeof(buffer)而不是1024,这样即使调整了缓冲区的大小,也可以确保大小正确


客户的其他意见:

  • 变量hello是无用的

  • 根据定义,sizeof(char)的值为1,因此sizeof(char)*N可以处处替换为N

  • 不要将读取字符与文本10和27进行比较,请与“\n”和“\e”进行比较

  • 您不需要在输入中管理EOF,因此您需要将读取的字符保存为int而不是char(如buf[i]is),以将其与EOF进行比较

在服务器中,变量步骤是无用的


因此,您使用SOCK_STREAM,因此您的套接字是一个流(tcp而非udp),这意味着您不能假设每次调用read时读取的数据的大小,我的意思是,如果客户端发送了N个字节,这并不意味着服务器将在相应的读取中读取N个字节(如果我可以说“对应”,因为没有对应;-)

如果输入azeqsd,则假定其他问题已修复\n您发送了azeqsd,但可能在服务器端,您将阅读
if (++i >= N) {
else if (++i >= N) {
send(sock , buf , strlen(buf) , 0 );
 send(sock , buf , i , 0 );
char buffer[1024];
...
valread = read( new_socket , buffer, 1024);
if(valread == 0)
  break;
printf("%s", buffer );
 char buffer[1024];
 ...
 while ((valread = read(new_socket, buffer, sizeof(buffer)-1)) > 0) {
   buffer[valread ] = 0;
   printf("%s", buffer);
 }