[英]tcp server blocking read in C
我想实现一个带有阻止读取的简单TCP服务器,该服务器接收从客户端一个字符接一个字符发送的消息,直到分隔符为止。 收到消息后,它必须等到下一条消息出现。 这是我的伪代码:
// Messages sent from the client
char *message1 = "mssg1\n"
char *message2 = "mssg2\n"
// On server side
char buffer;
char completeMessage[5]
while(1){
while(buffer != '\n'){
recv(sock, &buffer, 1, 0); // 1 is the read size
if(buffer != '\n') {
printf("buffer: %c\n", buffer);
completeMessage[n] = buffer;
count ++;
}
else{
printf("Complete message: %s\n", completeMessage);
count = 0;
}
}
}
结果如下:
buffer: m
buffer: s
buffer: s
buffer: g
buffer: 1
Complete message: mssg1
buffer:
buffer:
buffer:
buffer:
buffer:
buffer:
// Error due to buffer overflow
我不知道为什么recv而不是等待下一个消息字符(阻止读取),而是继续读取空格。 我的问题如下:
recv真的是套接字阻止读取功能吗?
是的,除非您使句柄不阻塞。
代码中是否有错误或遗漏? ,
您没有检查recv
返回什么。 0
表示EOF, -1
表示错误。
您无需检查缓冲区的容量,因此有可能缓冲区溢出。
您不会像printf %s
所要求的那样用NUL终止completeMessage
的字符串。
还有其他建议可以实施吗?
您不应该一次读一个字符!
#define BUFFER_SIZE (64*1024)
char* extract_string(const char* start, const char* end) {
size_t len = end - start;
char* dst = malloc(len+1);
if (dst == NULL)
return NULL;
memcpy(dst, src, len);
dst[len] = '\0';
return dst;
}
{
char buf_start[BUFFER_SIZE];
char* buf_end = buf_start + BUFFER_SIZE;
char* window_start = buf_start;
char* window_end = buf_start;
while (1) {
if (window_end == buf_end) { // No more space.
fprintf(stderr, "Overly large message");
return 0;
}
ssize_t rv = recv(sock, window_end, buf_end-window_end, 0);
if (rv == -1) { // Error.
perror("recv");
return 0;
}
if (rv == 0) { // EOF.
return 1;
}
while (rv--) {
if (*(window_end++) == '\n') {
char* msg = extract_string(window_start, window_end-1); // Excl LF.
if (msg == NULL) {
fprintf(stderr, "Out of memory");
return 0;
}
// Do something with msg
printf("Complete message: %s\n", msg);
free(msg);
window_start = window_end;
}
}
memmove(buf_start, window_start, window_end-window_start);
window_end -= (window_start - buf_start);
window_start = buf_start;
}
}
您的代码有很多问题,即您忽略了recv()
的返回值,在打印buffer
之前没有将buffer
终止为空,并且没有保护自己免受缓冲区溢出的影响。
尝试类似这样的方法:
char ch, *tmp, *message = NULL;
int ret, length = 0, allocated = 0;
while (1)
{
ret = recv(sock, &ch, 1, 0);
if (ret <= 0)
{
if (ret < 0)
printf("Read error: %d\n", errno); // or WSAGetLastError() on Windows
else
printf("Client disconnected\n");
break;
}
if (ch == '\n')
{
if ((length > 0) && (message[length-1] == '\r'))
--length;
printf("Complete message: '%.*s'\n", length, message);
length = 0;
}
else
{
printf("ch: %c\n", ch);
if (length == allocated)
{
if (length >= 5000) // some max length of your choosing...
{
printf("Message length too large!\n");
break;
}
// just for example. You should use a more robust growth algorithm in production code...
tmp = (char*) realloc(message, allocated + 10);
if (!tmp)
{
printf("Memory allocation failed\n");
break;
}
message = tmp;
allocated += 10;
}
message[length] = ch;
++length;
}
}
free(message);
或者,不要按字符阅读。 从任何给定读取的套接字中读取尽可能多的数据,并将其全部存储在不断增长的缓冲区中,然后扫描该缓冲区以获取完整的消息,例如:
char *buffer = (char*) malloc(100);
if (!buffer)
{
printf("Memory allocation failed\n");
}
else
{
int ret, offset, remaining, inbuf = 0, allocated = 100;
char *ptr;
while (1)
{
if (inbuf == allocated)
{
if (inbuf >= 5000) // some max length of your choosing...
{
printf("Buffer length too large!\n");
break;
}
// just for example. You should use a more robust growth algorithm in production code...
tmp = (char*) realloc(buffer, allocated + 100);
if (!tmp)
{
printf("Memory allocation failed\n");
break;
}
buffer = tmp;
allocated += 100;
}
ret = recv(sock, buffer+inbuf, allocated-inbuf, 0);
if (ret <= 0)
{
if (ret < 0)
printf("Read error: %d\n", errno); // or WSAGetLastError() on Windows
else
printf("Client disconnected\n");
break;
}
printf("Received: %.*s\n", ret, buffer+inbuf);
inbuf += ret;
while (ptr = (char*)memchr(buffer, '\n', inbuf))
{
offset = (ptr-buffer);
if ((offset > 0) && (buffer[offset-1] == '\r'))
--offset;
printf("Complete message: '%.s'\n", offset, buffer);
++ptr;
remaining = (inbuf - (ptr - buffer));
if (remaining > 0)
memmove(buffer, ptr, remaining);
inbuf = remaining;
}
}
free(buffer);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.