如何通过缓冲区传递整数?

时间:2016-09-13 16:14:51

标签: c sockets client-server

我想创建一个可以读取某些数字而不是字符串的套接字,以便我可以对它们执行一些操作。 如何发送整数而不是字符串 这是我目前的计划:

  int main(int argc, char *argv[])
{ 
int sockfd, newsockfd, port, clilen;
struct sockaddr_in serv_addr, cli_addr;

if (argc < 2)
error("ERROR, no port provided\n");
port = atoi(argv[1]);

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); //host to network

if (bind(sockfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR binding to socket");

listen(sockfd,2);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,(struct sockaddr *)&cli_addr, &clilen);
int n;
void* buffer[256];
n = read(newsockfd,buffer,255);


if (n < 0) error("ERROR reading from socket");
printf("Message received:%d\n",d);

n = write(newsockfd,buffer, strlen((char *)buffer));
if (n < 0)
error("ERROR writing back to socket");

return 0;}

我试过了:

int n= 5;
 write(newsockfd,&n, sizeof(int));

但是在客户端(也是一个void *缓冲区),它似乎没有读取任何内容。任何人都可以帮助我如何纠正这个问题?

一种解决方案可能是传递字符串然后转换为int等。但这是正确的方法吗?

2 个答案:

答案 0 :(得分:2)

问题是双重的:

第一个问题是声明void* buffer[256]声明buffer是一个256个指向void的数组,而不是我想的那个。相反,如果你想要一个256字节的数组,只需char buffer[256]

第二个问题是,在接收方,您将数据视为字符串,但它不是字符串,而是二进制数据值。

第二个问题可以通过两种方式解决:将整数转换为字符串,然后发送该字符串。或者您收到整数的原始数据,并将其转换为int。第一个解决方案涉及sprintf,另一个解决方案涉及memcpy或指针和转换。

对于上面的第一个解决方案,您可以执行以下操作:

char temp[32];
snprintf(temp, sizeof temp, "%d", n);
write(newsockfd, temp, sizeof temp);

在接收端,您将其读作字符串:

char buffer[32];
n = read(newsockfd, buffer, sizeof buffer);
if (n <= 0)
{
    // Error or connection closed
}

// TODO: Since TCP is a streaming protocol, we could actually receive
//       less than the number of bytes we asked to read, so we need
//       to read in a loop

// Print the received data as a string
printf("Received '%s'\n", buffer);  // Works because the sender sent with the terminator

// Convert to integer
int i = strtol(buffer, NULL, 10);
printf("Received %d\n", i);

对于上面的第二个解决方案,将整数值作为原始二进制数据发送,但是当收到它时,请执行类似

的操作
char buffer[32];
n = read(newsockfd, buffer, sizeof buffer);
if (n <= 0)
{
    // Error or connection closed
}

// TODO: Since TCP is a streaming protocol, we could actually receive
//       less than the number of bytes we asked to read, so we need
//       to read in a loop

int i = *(int *) buffer;
printf("Received %d\n", i);

请注意,此答案中写的第二个解决方案依赖于发件人和收件人具有相同的endianness,以及int的相同大小(可能不会总是如此)。

最安全的方法通常是在发送端转换为字符串,并将字符串作为字符串接收。即第一个解决方案。

答案 1 :(得分:1)

我想修改提供的清晰回答Joachim Pileborg

var dbcontext = new ApplicationDbContext(); //foo table is empty
var entry = new Entry { DateTime = DateTime.Now };
dbcontext.Foo.Add();
dbcontext.SaveChanges();
dbcontext.Entry(entry).Reload(); //doesnt suffer from the quirks of dbcontext.Gigs.First()

您知道自己接收了多少字节,因此没有理由阅读更多字节。循环处理他警告的情况:读取(2)可能无法读取所有4个字节(在这种情况下不太可能,但通常不会)。

您始终可以从int value, todo = sizeof(value); char *p = (void*) &value; while ( (n = read(newsockfd, p, todo)) < todo ) { if( n == 0 ) { /* handle eof and break */ } if( n < 0 ) { /* handle error and break */ } todo -= n; p += n } if( todo == 0 ) { printf("Received %d\n", value); } 获取char *,并将任何指针传递给接受void *的函数。你不能做的,便携,是

void *

因为不保证字符数组具有整数对齐。在某些架构上,这会引发SIGBUS。如果您读入字符数组,那么将这些字节解释为整数的安全方法是

char buffer[32];
...
int i = *(int *) buffer;