套接字编程--recv()未正确接收数据
我看过类似的线程,但似乎找不到任何可以解决我的问题 我正在编程一个服务器,它可以从客户端发送的路径发送一个图像(jpg)文件。我使用C中的send/recv函数来实现这一点 我一次读取一块数据并将其发送给接收内容的客户端,然后将其写入某个位置以构建文件 问题是“recv”未接收“send”发送的字节数 作为调试的一部分,我尝试了不同的缓冲区大小,“128”缓冲区大小并没有给我带来任何问题,并且成功地传输和构建了文件 但是,对于“32”位和“64”位缓冲区,“recv”在最后一块接收“32”位或“64”位数据,即使服务器发送的数据小于“32”位或“64”位。而且,对于'256'、'512'、'1024'等,即使服务器根据缓冲区大小发送完整的数据块(即'256'或'512',recv'也仅在响应的一个位置返回'128'位 如果您能给我一些调试方面的建议,我将不胜感激。以下代码仅适用于相关部分,但如果有人需要,我可以提供更多 //客户端代码套接字编程--recv()未正确接收数据,c,sockets,C,Sockets,我看过类似的线程,但似乎找不到任何可以解决我的问题 我正在编程一个服务器,它可以从客户端发送的路径发送一个图像(jpg)文件。我使用C中的send/recv函数来实现这一点 我一次读取一块数据并将其发送给接收内容的客户端,然后将其写入某个位置以构建文件 问题是“recv”未接收“send”发送的字节数 作为调试的一部分,我尝试了不同的缓冲区大小,“128”缓冲区大小并没有给我带来任何问题,并且成功地传输和构建了文件 但是,对于“32”位和“64”位缓冲区,“recv”在最后一块接收“32”位或“
#define BUFFER_SIZE 4096
#define HEADER_LEN 512
const char * const scheme = "GETFILE";
const char* const method = "GET";
const char * const end_marker = "\\r\\n\\r\\n";
struct gfcrequest_t
{
int filelen;
char cport[12];
char servIP[50];
gfstatus_t ret_status;
char spath[1024];
int tot_bytes;
char filecontent[BUFFER_SIZE];
void (*fl_handler)(void *, size_t, void *);
void * fDesc;
void (*head_handler)(void *, size_t, void *);
void * headarg;
};
static pthread_mutex_t counter_mutex;
gfcrequest_t *gfc;
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
static char *stringFromError(gfstatus_t stat)
{
static const char *strings[] = {"GF_OK", "GF_FILE_NOT_FOUND", "GF_ERROR", "GF_INVALID"};
return strings[stat];
}
int getFileRequestHeader(char * req_header)
{
return snprintf(req_header,HEADER_LEN, "%s%s%s%s", scheme, method,gfc->spath, end_marker);
// return snprintf(req_header,HEADER_LEN, "%s%s%s%s", scheme, method,"/courses/ud923/filecorpus/yellowstone.jpg", end_marker);
}
gfcrequest_t *gfc_create()
{
gfc = (gfcrequest_t*)malloc(1* sizeof(gfcrequest_t));
return gfc;
}
void gfc_set_server(gfcrequest_t *gfr, char* server)
{
strcpy(gfr->servIP, server);
}
void gfc_set_path(gfcrequest_t *gfr, char* path)
{
strcpy(gfr->spath, path);
}
void gfc_set_port(gfcrequest_t *gfr, unsigned short port)
{
snprintf(gfr->cport,12, "%u",port);
}
void gfc_set_headerfunc(gfcrequest_t *gfr, void (*headerfunc)(void*, size_t, void *))
{
gfr->head_handler = headerfunc;
}
void gfc_set_headerarg(gfcrequest_t *gfr, void *headerarg)
{
/*have to change this...*/
gfr->headarg = headerarg;
}
int isEndMarker(char *iheader, int start)
{
char *marker = "\\r\\n\\r\\n";
int i = 0; int ind=0;
while (ind <= 7)
{
if (iheader[start++] == marker[ind++])
{
continue;
}
return 0;
}
return 1;
}
int getFileLen(char *resp_header, gfcrequest_t *gfr)
{
char scheme[8];
char status[4];
int istatus;
char filelen[12];
int contentlen = 0;
int fileindex = 0;
char end_marker[12];
int fexit=0;
int end=0;
sscanf(resp_header, "%7s%3s", scheme, status);
istatus = atoi(status);
if (istatus == 200)
{
gfr->ret_status = GF_OK;
}
else if (istatus == 400)
{
gfr->ret_status = GF_FILE_NOT_FOUND;
}
else if (istatus == 500)
{
gfr->ret_status = GF_ERROR;
}
if (!strcmp(scheme, "GETFILE") && (istatus == 200 || istatus == 400 || istatus == 500))
{
int index = 10;
while(1)
{
if (resp_header[index] == '\\')
{
end = isEndMarker(resp_header, index);
}
if (end)
break;
filelen[fileindex++] = resp_header[index++];
}
filelen[fileindex] = '\0';
}
int head_len = strlen(scheme) + strlen(status) + strlen(filelen) + 8;
return atoi(filelen);
}
void gfc_set_writefunc(gfcrequest_t *gfr, void (*writefunc)(void*, size_t, void *))
{
gfr->fl_handler = writefunc;
}
void gfc_set_writearg(gfcrequest_t *gfr, void *writearg)
{
gfr->fDesc = writearg;
}
int gfc_perform(gfcrequest_t *gfr){
struct addrinfo hints, *servinfo, *p;
int sockfd, rv, totalBytesRcvd;
char req_header[HEADER_LEN];
int bytesRcvd;
int header_len;
char s[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof(hints));
memset(req_header,0,sizeof(req_header));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; //use my IP
if ((rv = getaddrinfo(NULL, gfr->cport, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1)
{
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "client: failed to connect\n");
return 2;
}
//printf("connected...\n");
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof(s));
//Ahsan
// printf("Before getFileRequestHeader...\n");
header_len = getFileRequestHeader(req_header);
//printf("Header Description:%s, Header Len: %u\n", req_header, header_len);
if (send(sockfd, req_header, header_len, 0) != header_len)
perror("send() sent a different number of bytes than expected");
if ((bytesRcvd = recv(sockfd, gfr->filecontent, BUFFER_SIZE, 0)) <= 0)
perror("recv() failed or connection closed prematurely");
//printf("Header Received: %s\n", gfr->filecontent);
gfr->filelen = getFileLen(gfr->filecontent, gfr);
//printf("File Length: %d\n", gfr->filelen);
/* Receive the same string back from the server */
int req_no=1;
gfr->tot_bytes = 0;
while ( 1 )
{
printf("Request: %d ", req_no++);
ssize_t nb = recv( sockfd, gfr->filecontent, BUFFER_SIZE, 0 );
if ( nb == -1 ) err( "recv failed" );
if ( nb == 0 ) {printf("zero bytes received...breaking");break;} /* got end-of-stream */
gfr->fl_handler(gfr->filecontent, nb, gfr->fDesc);
gfr->tot_bytes += nb;
printf("Received Bytes: %zd Total Received Bytes: %d\n", nb, gfr->tot_bytes);
}
return 0;
}
/*
* Returns the string associated with the input status
*/
char* gfc_strstatus(gfstatus_t status)
{
return stringFromError(status);
}
gfstatus_t gfc_get_status(gfcrequest_t *gfr){
return gfr->ret_status;
}
size_t gfc_get_filelen(gfcrequest_t *gfr)
{
return gfr->filelen;
}
size_t gfc_get_bytesreceived(gfcrequest_t *gfr)
{
return gfr->tot_bytes;
}
void gfc_cleanup(gfcrequest_t *gfr)
{
free(gfr);
gfr=NULL;
}
void gfc_global_init()
{
;
// pthread_mutex_lock(&counter_mutex);
//
// gfc = (gfcrequest_t*)malloc(1* sizeof(gfcrequest_t));
//
// pthread_mutex_unlock(&counter_mutex);
}
void gfc_global_cleanup()
{
;
// pthread_mutex_lock(&counter_mutex);
//
// free(gfc);
//
// pthread_mutex_unlock(&counter_mutex);
}
#定义缓冲区大小4096
#定义标题_len512
const char*const scheme=“GETFILE”;
const char*const method=“GET”;
常量字符*常量结束标记=“\\r\\n\\r\\n”;
结构gfcrequest\t
{
int filelen;
char-cport[12];
char-servIP[50];
gfstatus\t ret\u status;
char spath[1024];
int tot_字节;
char filecontent[缓冲区大小];
空隙(*fl_handler)(空隙*,尺寸,空隙*);
无效*fDesc;
空隙(*封头)(空隙*,尺寸,空隙*);
void*headarg;
};
静态pthread_mutex_t counter_mutex;
gfcrequest_t*gfc;
//获取sockaddr、IPv4或IPv6:
void*get\u in\u addr(结构sockaddr*sa)
{
如果(sa->sa_族==AF_INET)
{
return&(((struct sockaddr_in*)sa)->sin_addr);
}
返回((结构sockaddr_in6*)sa)->sin6_addr);
}
静态字符*stringFromError(gfstatus\u t stat)
{
静态常量字符*字符串[]={“GF_确定”、“GF_文件未找到”、“GF_错误”、“GF_无效”};
返回字符串[stat];
}
int getFileRequestHeader(char*req_头)
{
返回snprintf(请求头、头、长度、%s%s%s)、方案、方法、gfc->spath、结束标记);
//返回snprintf(请求标题、标题标题、标题、“%s%s%s”、方案、方法、“/courses/ud923/filecorpus/yellowstone.jpg”、结束标记);
}
gfcrequest_t*gfc_create()
{
gfc=(gfcrequest_t*)malloc(1*sizeof(gfcrequest_t));
返回gfc;
}
无效gfc_集_服务器(gfcrequest_t*gfr,char*server)
{
strcpy(gfr->servIP,服务器);
}
无效gfc\u集\u路径(gfcrequest\u t*gfr,char*path)
{
strcpy(gfr->spath,路径);
}
无效gfc_set_端口(gfcrequest_t*gfr,无符号短端口)
{
snprintf(gfr->cport,12,“%u”,端口);
}
无效gfc\U套件\U头Func(gfcrequest\U t*gfr,无效(*headerfunc)(无效*,大小,无效*)
{
gfr->head\u handler=headerfunc;
}
无效gfc\U集合\U头RG(gfcrequest\U t*gfr,无效*头RG)
{
/*我必须改变这个*/
gfr->headerarg=headerarg;
}
int ISENDMERKER(字符*I头,int开始)
{
char*marker=“\\r\\n\\r\\n”;
int i=0;int ind=0;
而(ind ret_status=GF_OK;
}
否则如果(istatus==400)
{
gfr->ret\u status=未找到GF\u文件;
}
否则如果(istatus==500)
{
gfr->ret\U状态=GF\U错误;
}
如果(!strcmp(scheme,“GETFILE”)&&(istatus==200 | | istatus==400 | | istatus==500))
{
int指数=10;
而(1)
{
如果(响应头[索引]='\\')
{
end=ISENDMERKER(相应的标题、索引);
}
若(完)
打破
filelen[fileindex++]=resp_头[index++];
}
filelen[fileindex]='\0';
}
int head_len=strlen(方案)+strlen(状态)+strlen(文件)+8;
返回atoi(文件);
}
空gfc\U集\U写UNC(gfcrequest\U t*gfr,空(*写UNC)(空*,大小,空*)
{
gfr->fl_handler=writefunc;
}
无效gfc\u集合\u写入(gfcrequest\u t*gfr,无效*writearg)
{
gfr->fDesc=writearg;
}
内部gfc_表演(gfcrequest_t*gfr){
结构addrinfo提示,*servinfo,*p;
int sockfd、rv、TOTALLBYTESRCVD;
字符请求标头[标头长度];
int bytesRcvd;
int header_len;
字符s[INET6_ADDRSTRLEN];
memset(&hints,0,sizeof(hints));
memset(req_头,0,sizeof(req_头));
hits.ai_family=AF_unsec;
hits.ai_socktype=SOCK_流;
hits.ai_flags=ai_PASSIVE;//使用我的IP
if((rv=getaddrinfo(NULL,gfr->cport,&hints,&servinfo))!=0)
{
fprintf(标准,“getaddrinfo:%s\n”,gai_strerror(rv));
返回1;
}
//循环浏览所有结果并连接到第一个我们可以
for(p=servinfo;p!=NULL;p=p->ai_next)
{
if((sockfd=socket(p->ai_系列,p->ai_socktype,p->ai_协议))=-1)
{
perror(“客户端:套接字”);
继续;
}
如果(连接(sockfd,p->ai_addr,p->ai_addrlen)=-1)
{
关闭(sockfd);
perror(“客户:连接”);
继续;
}
打破
}
if(p==NULL)
{
fprintf(stderr,“客户端:连接失败\n”);
返回2;
}
//printf(“已连接…\n”);
inet_ntop(p->ai_family,get_in_addr((struct sockaddr*)p->ai_addr),s,sizeof(s));
//阿桑
//printf(“getFileRequestHeader之前…\n”);
header\u len=getFileRequestHeader(请求头);
//printf(“标题说明:%s,标题长度:%u\n”,请求标题,标题长度);
if(发送(sockfd,请求标头,标头长度,0)!=标头长度)
perror(“send()发送的字节数与预期的不同”);
如果((bytesRcvd=recv(sockfd,gfr->filecontent,BUFFER_SIZE,0))filecontent);
gfr->filelen=getFileLen(gfr->filecontent,gfr);
//printf(“文件长度:%d\n”,gfr->filelen);
/*收到相同的str
struct gfcontext_t
{
int sockfd;
int clntSock;
};
struct gfserver_t
{
char port[12];
unsigned short max_npending;
char fpath[256];
ssize_t (*fp_handler)(gfcontext_t *ctx, char *, void*);
int *handler_arg;
};
/*Variable decalation*/
static gfserver_t *gfserv;
static gfcontext_t *gfcontext;
int isEndMarker(char *iheader, int start)
{
char *marker = "\\r\\n\\r\\n";
int i = 0; int ind=0;
while (ind <= 7)
{
if (iheader[start++] == marker[ind++])
{
//printf("Header Char:%c Marker:%c\n", iheader[start], marker[ind]);
//start++;
continue;
}
return 0;
}
//printf("Its a marker!!!\n");
return 1;
}
int parseHeader(char *iheader, gfserver_t *gfs, int hlen)
{
//"GETFILEGET/courses/ud923/filecorpus/road.jpg\r\n\r\n"
char scheme[8];
char method[4];
// char path[256];
int pathindex = 0;
char end_marker[12];
int end = 0;
int fexit=0;
sscanf(iheader, "%7s%3s", scheme, method);
int i=10;
if (iheader[i] == '/')
{
// printf("Path has started...\n");
if (!strcmp(scheme, "GETFILE") && !strcmp(method, "GET"))
{
while(1)
{
if (iheader[i] == '\\')
{
end = isEndMarker(iheader, i);
}
if (end)
break;
gfs->fpath[pathindex++] = iheader[i++];
}
gfs->fpath[pathindex] = '\0';
}
}
printf("Scheme: %s Method:%s Path:%s\n", scheme, method, gfs->fpath);
return 0;
}
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
ssize_t gfs_sendheader(gfcontext_t *ctx, gfstatus_t stat, size_t file_len)
{
char resp_header[MAX_REQUEST_LEN];
char end_marker[12] = "\\r\\n\\r\\n";
sprintf(resp_header, "GETFILE%d%zd%s",stat, file_len, end_marker);
printf("Response: %s\n", resp_header);
if (send(ctx->clntSock, resp_header, MAX_REQUEST_LEN, 0) != MAX_REQUEST_LEN)
perror("send() failed");
return 0;
}
ssize_t gfs_send(gfcontext_t *ctx, void *data, size_t len)
{
size_t total = 0;
size_t bytesLeft = len;
size_t n;
int debug_req=1;
while (total < len)
{
n = send(ctx->clntSock, data+total, bytesLeft, 0);
if (n == -1) { printf("Nothing to send...\n"); break; }
fprintf(stderr, "Tries: %d Bytes Sent: %zu\n", debug_req++, n);
total += n;
bytesLeft -= n;
}
// if ( shutdown( ctx->clntSock, SHUT_WR ) == -1 ) err( "socket shutdown failed" );
return total;
}
void gfs_abort(gfcontext_t *ctx){
close(ctx->clntSock);
close(ctx->sockfd);
free(ctx);
free(gfserv);
perror("aborting...");
exit(1);
}
gfserver_t* gfserver_create()
{
gfserv = (gfserver_t*) malloc(1 * sizeof(gfserver_t));
gfcontext = (gfcontext_t*) malloc(1*sizeof(gfcontext_t));
return gfserv;
}
void gfserver_set_port(gfserver_t *gfs, unsigned short port)
{
//set port number in gfs structure
snprintf(gfs->port,12, "%u",port);
}
void gfserver_set_maxpending(gfserver_t *gfs, int max_npending)
{
//set maxpending connections
gfs->max_npending = max_npending;
}
void gfserver_set_handler(gfserver_t *gfs, ssize_t (*handler)(gfcontext_t *, char *, void*))
{
gfs->fp_handler = handler;
}
void gfserver_set_handlerarg(gfserver_t *gfs, void* arg)
{
gfs->handler_arg = (int *)arg;
}
void gfserver_serve(gfserver_t *gfs)
{
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage clntAddr; //connectors address information
socklen_t clntSize;
int yes = 1;
char s[INET6_ADDRSTRLEN];
int rv;
int rcvMsg = 0;
char recvBuff[MAX_REQUEST_LEN];
char *req_path;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; //using stream socket instead of datagrams
hints.ai_flags = AI_PASSIVE; //use my IP
if ((rv = getaddrinfo(NULL, gfs->port, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((gfcontext->sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("server: socket");
continue;
}
//get rid of 'address already in use' error.
if (setsockopt(gfcontext->sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
if (bind(gfcontext->sockfd, p->ai_addr, p->ai_addrlen) == -1)
{
close(gfcontext->sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "server: failed to bind.\n");
return 2;
}
freeaddrinfo(servinfo); // no need of servinfo structure anymore
if (listen(gfcontext->sockfd, gfs->max_npending) == -1)
{
perror("listen");
exit(1);
}
//printf("server: waiting for connetions...\n");
while(1)
{
clntSize = sizeof(clntAddr);
gfcontext->clntSock = accept(gfcontext->sockfd, (struct sockaddr *)&clntAddr, &clntSize);
if (gfcontext->clntSock == -1)
{
perror("accept");
continue;
}
inet_ntop(clntAddr.ss_family, get_in_addr((struct sockaddr *)&clntAddr), s, sizeof(s));
//printf("server: got connection from %s\n", s);
if (!fork())
{ // this is the child process
if ((rcvMsg = recv(gfcontext->clntSock, recvBuff, MAX_REQUEST_LEN, 0)) < 0)
{
perror("recv() failed");
exit(1);
}
/*Still to parse received request...*/
//printf("Recd Header: %s, Recd %d bytes\n",recvBuff, rcvMsg);
/*Parse the received header...*/
int len = parseHeader(recvBuff, gfs, rcvMsg);
//printf("Requested Path: %s\n", gfs->fpath);
if (gfs->fp_handler(gfcontext, gfs->fpath, NULL) < 0)
{
printf("some problem...\n");
}
if ( shutdown( gfcontext->clntSock, SHUT_WR ) == -1 ) err( "socket shutdown failed" );
//close(gfcontext->clntSock);
}
}
}
//Server gf_send is being called from following function handler function:
Handler:
ssize_t handler_get(gfcontext_t *ctx, char *path, void* arg){
int fildes;
size_t file_len, bytes_transferred;
ssize_t read_len, write_len;
char buffer[BUFFER_SIZE];
printf("Path: %s\n", path);
if( 0 > (fildes = content_get(path)))
return gfs_sendheader(ctx, GF_FILE_NOT_FOUND, 0);
/* Calculating the file size */
file_len = lseek(fildes, 0, SEEK_END);
gfs_sendheader(ctx, GF_OK, file_len);
/* Sending the file contents chunk by chunk. */
int req=1;
bytes_transferred = 0;
while(bytes_transferred < file_len){
read_len = pread(fildes, buffer, BUFFER_SIZE, bytes_transferred);
if (read_len <= 0){
fprintf(stderr, "handle_with_file read error, %zd, %zu, %zu", read_len, bytes_transferred, file_len );
gfs_abort(ctx);
return -1;
}
printf("Request No: %d ", req++);
write_len = gfs_send(ctx, buffer, read_len);
if (write_len != read_len){
fprintf(stderr, "handle_with_file write error");
gfs_abort(ctx);
return -1;
}
bytes_transferred += write_len;
}
printf("Total Bytes sent to client: %zu\n", bytes_transferred);
return bytes_transferred;
}
size_t total = 0;
while ( total != len ) {
ssize_t nb = send( s, data + total, len - total, 0 );
if ( nb == -1 ) err( "send failed" );
total += nb;
}
if ( shutdown( s, SHUT_WR ) == -1 ) err( "socket shutdown failed" );
/* also need to close client socket, see below */
char buffer[BUFFER_SIZE]; /* somewhere, might be static */
size_t total = 0; /* everything received */
while ( 1 ) {
ssize_t nb = recv( s, buffer, BUFFER_SIZE, 0 );
if ( nb == -1 ) err( "recv failed" );
if ( nb == 0 ) break; /* got end-of-stream */
if ( write( file_fd, buffer, nb ) == -1 ) err( "file write failed" );
total += nb;
}
/* send an ack here */
if ( close( s ) == -1 ) err( "socket close failed" );
if ( close( file_fd )) err( "file close failed" );
printf( "received and saved total of %zu bytes\n", total );
gfr->fl_handler(gfr->filecontent, BUFFER_SIZE, gfr->fDesc);
gfr->fl_handler(gfr->filecontent, bytesRcvd, gfr->fDesc);