C socket:接收并发送所有数据
Posted
技术标签:
【中文标题】C socket:接收并发送所有数据【英文标题】:C socket: recv and send all data 【发布时间】:2012-11-08 21:46:24 【问题描述】:我想获得类似这样的行为:
-
服务器运行
客户端运行
客户端键入“帮助”或其他命令
服务器响应适当
转到3
问题是,当我的函数 excCommand("help") 运行时,只接收并打印了一小段文本。 我的文本文件是这样的:
COMMAND HELP:
help - Display help
quit - Shutdown client
只打印命令帮助。 另一个问题是,当我键入命令时,没有打印任何内容,并且在 2 个命令客户端退出之后。 尤其是这件作品:
while (quit)
getLine("client> ", command, 10);
if (strcmp(command, "quit") == 0)
quit = 0;
else
excCommand(command);
这是服务器:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
int main(int argc, char *argv[])
if (argc != 2)
ErrorWithUserMessage("Parameter(s)", "<Server Port>");
char *service = argv[1];
int servSock = SetupTCPServerSocket(service);
if (servSock < 0)
ErrorWithUserMessage("SetupTCPServerSocket() failed: ", "unable to establish");
unsigned int childProcessCount = 0;
while (1)
int clntSock = AcceptTCPConnection(servSock);
pid_t processID = fork();
if (processID < 0)
ErrorWithSystemMessage("fork() failed");
else if (processID == 0)
close(servSock);
HandleTCPClient(clntSock);
exit(EXIT_SUCCESS);
printf("with child process: %d\n", processID);
close(clntSock);
childProcessCount++;
//clean up zombies
while (childProcessCount)
processID = waitpid((pid_t) - 1, NULL, WNOHANG);
if (processID < 0)
ErrorWithSystemMessage("waitpid() failed");
else if (processID == 0)
break;
else
childProcessCount--;
处理程序:
void HandleTCPClient(int clntSock)
char buffer[BUFSIZE];
ssize_t numBytesRcvd = recv(clntSock, buffer, BUFSIZE, 0);
buffer[numBytesRcvd] = '\0';
if (numBytesRcvd < 0)
ErrorWithSystemMessage("recv() failed");
if (strcmp(buffer, "help") == 0)
FILE *fp = fopen("help.txt", "r");
if (fp)
char line[128];
while (fgets(line, sizeof(line), fp) != NULL)
if (send(clntSock, line, sizeof(line), 0) < 0)
ErrorWithSystemMessage("send() failed");
fclose(fp);
close(clntSock);
这是我的客户:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "common.h"
int sock;
void getLine(char *message, char *buf, int maxLen)
printf("%s", message);
fgets(buf, maxLen, stdin);
buf[strlen(buf) - 1] = 0;
void excCommand(char *command)
if ( send(sock, command, strlen(command), 0) < 0)
ErrorWithSystemMessage("send() failed");
char replyMessage[BUFSIZE];
ssize_t numBytesRecv = 0;
do
numBytesRecv = recv(sock, replyMessage, BUFSIZE, 0);
if ( numBytesRecv < 0)
ErrorWithSystemMessage("recv() failed");
printf("%s\n", replyMessage);
memset(&replyMessage, 0, sizeof(replyMessage));
while (numBytesRecv > 0);
void PrintFile(const char *filename)
FILE *fp;
fp = fopen(filename, "r");
if (fp)
char line[128];
while (fgets(line, sizeof(line), fp) != NULL)
fputs(line, stdout);
fputs("\n", stdout);
fclose(fp);
int main(int argc, char *argv[])
int quit = 1;
char command[10];
if (argc < 2 || argc > 3)
ErrorWithUserMessage("Parameter(s)", "<Server Address> <Server Port>");
char *server = argv[1];
char *service = argv[2];
sock = SetupTCPClientSocket(server, service);
if (sock < 0)
ErrorWithUserMessage("SetupTCPClientSocket() failed: ", "unable to connect");
printf("Connection established!\n\n");
PrintFile("menu.txt");
excCommand("help");
while (quit)
getLine("client> ", command, 10);
if (strcmp(command, "quit") == 0)
quit = 0;
else
excCommand(command);
fputs("\n", stdout);
close(sock);
exit(EXIT_SUCCESS);
抱歉这么啰嗦
【问题讨论】:
下次遇到问题时,试着构建一个尽可能小的程序来模拟类似的行为,这样人们会更容易理解问题所在并为您提供帮助。 你是对的,对不起:( 【参考方案1】:recv()
和 send()
函数不保证发送/接收所有数据(请参阅man recv、man send)
您需要实现自己的send_all()
和recv_all()
,类似
bool send_all(int socket, void *buffer, size_t length)
char *ptr = (char*) buffer;
while (length > 0)
int i = send(socket, ptr, length);
if (i < 1) return false;
ptr += i;
length -= i;
return true;
以下指南可能对您有所帮助Beej's Guide to Network Programming
【讨论】:
好的,但是另一方面,我怎么知道我必须调用recv()多少次? 可以在每条消息前加上消息的长度。而recv()固定的字节数代表消息大小的长度,然后调用recv(message_size) 这个 send_all() 函数不起作用。它应该将'buffer'声明为'char *';每次“i”为正时,它应该将“buffer”增加“i”;当然,如果 'i' 是负数,它应该完全停止。 整件事都是不必要的。send()
方法会阻塞,直到所有数据都已传输或发生错误。当然是在阻塞模式下,但这就是这段代码所假设的。非阻塞实现必须使用select()
才能知道下一次写入的时间。【参考方案2】:
常见问题。
void excCommand(char *command)
if ( send(sock, command, strlen(command), 0) < 0)
ErrorWithSystemMessage("send() failed");
char replyMessage[BUFSIZE];
ssize_t numBytesRecv = 0;
do
numBytesRecv = recv(sock, replyMessage, BUFSIZE, 0);
if ( numBytesRecv < 0)
ErrorWithSystemMessage("recv() failed");
printf("%s\n", replyMessage);
无效。 numBytesRecv
可能为零,在这种情况下根本没有消息,否则此时必须为正,因为您已经测试了负数,它表示消息的实际长度,不一定空终止。改为:
if (numBytesRecv == 0)
break;
printf("%.*s\n", numBytesRecv, replyMessage);
然后:
memset(&replyMessage, 0, sizeof(replyMessage));
毫无意义。删除。
while (numBytesRecv > 0);
此时您应该检查numBytesRecv < 0
并致电perror()
或其朋友之一。
【讨论】:
【参考方案3】:如果我必须继续,我选择在每个 send() 之前发送。
所以我首先有 3 个定义
#define BUFFSIZE 1024
#define CONT "CONT"
#define DONE "DONE"
然后发送我的数据
int send_to_socket(int sock, char *msg)
size_t len;
int ret[2];
len = strlen(msg);
ret[0] = send(sock, (len <= BUFFSIZE) ? DONE : CONT, 4, 0);
ret[1] = send(sock, msg, BUFFSIZE, 0);
if (ret[0] <= 0 || ret[1] <= 0)
perror("send_to_socket");
return (-1);
if (len > BUFFSIZE)
return (send_to_socket(sock, msg + BUFFSIZE));
return (1);
并收到它:
char *recv_from_socket(int cs)
char state[5];
char buff[BUFFSIZE+1];
char *msg;
int ret[2];
msg = NULL;
while (42)
bzero(state, 5);
bzero(buff, BUFFSIZE+1);
ret[0] = recv(cs, state, 4, 0);
ret[1] = recv(cs, buff, BUFFSIZE, 0);
if (ret[0] <= 0 || ret[1] <= 0)
perror("recv_from_socket");
return (NULL);
// strfljoin() is selfmade
// join the string and free the left argument to prevent memory leaks.
// return fresh new string
msg = (msg) ? ft_strfljoin(msg, buff) : strdup(buff);
if (strncmp(state, DONE, 4) == 0)
break ;
i++;
return (msg);
【讨论】:
strfljoin() 的链接:github.com/ale-batt/libft/blob/master/sources/string/…以上是关于C socket:接收并发送所有数据的主要内容,如果未能解决你的问题,请参考以下文章
安卓使用Socket发送中文,C语言服务端接收乱码问题解决方式