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