c写函数没有正确发送字节

时间:2013-01-22 13:55:34

标签: objective-c c sockets

我遇到了写功能无法正常工作的问题,如果它放在一个没有睡眠的循环中。我想要实现的是将文件从本地机器传输到远程FTP服务器以下代码工作正常但是写入函数没有正确传输字节,它只传输半个字节,它可以正常工作,睡眠阻塞循环。

 struct sockaddr_in
{
    int16_t sin_family;
    uint16_t sin_port;
    struct in_addr sin_addr;
    char sin_zero[8];
};

struct in_addr
{
    uint32_t s_addr;
};

struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
int isocket = socket(AF_INET,SOCK_STREAM,0);
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("some ip goes here");
servaddr.sin_port = htons(21);

char buf[1024];
int MAX_LENGTH = 1024;
char readBuf[MAX_LENGTH];
long cmd;

int res =  connect(isocket, (struct sockaddr_in *)&servaddr, sizeof(servaddr));

if(res < 0) {
    NSLog(@"problem connecting to server");
}

recv(isocket, (void *)readBuf,MAX_LENGTH, 0);
NSLog(@"response: %s",readBuf);

NSLog(@"Issuing command");

strcpy(buf, "USER foo\r\n");
cmd = send(isocket, (void *)buf, strlen(buf), 0); //send username


recv(isocket, (void *)readBuf,MAX_LENGTH, 0);
NSLog(@"response: %s",readBuf); //read response


strcpy(buf, "PASS *******\r\n");
cmd = send(isocket, (void *)buf, strlen(buf), 0);//send password

recv(isocket, (void *)readBuf, MAX_LENGTH, 0);
NSLog(@"response: %s",readBuf); //read response

strcpy(buf, "CWD /httpdocs/testing\r\n");
cmd = send(isocket, (void *)buf, strlen(buf), 0);//send directory

recv(isocket, (void *)readBuf, MAX_LENGTH, 0);
NSLog(@"response: %s",readBuf); //read response

strcpy(buf, "TYPE I\r\n");
cmd = send(isocket, (void *)buf, strlen(buf), 0);//set transfer type

recv(isocket, (void *)readBuf, MAX_LENGTH, 0);
NSLog(@"response: %s",readBuf); //read response

strcpy(buf, "PASV\r\n");
cmd = send(isocket, (void *)buf, strlen(buf), 0);//set transfer mode to passive

recv(isocket, (void *)readBuf, MAX_LENGTH, 0);
NSLog(@"response: %s",readBuf); //read response
NSString *pasvResponse = [NSString stringWithFormat:@"%s",readBuf];

strcpy(buf, "STOR mmov.jpeg\r\n");
cmd = send(isocket, (void *)buf, strlen(buf), 0);//start tranfering files


pasvResponse = [pasvResponse stringByReplacingOccurrencesOfString:@"227 Entering Passive Mode (" withString:@""];
pasvResponse = [pasvResponse stringByReplacingOccurrencesOfString:@")." withString:@""];
pasvResponse = [pasvResponse stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSArray *matches = [pasvResponse componentsSeparatedByString:@","];


NSString *ip = nil;
int port = 0;
if([matches count] > 2) {
    ip = [NSString stringWithFormat:@"%@.%@.%@.%@",matches[0],matches[1],matches[2],matches[3]];
    port = ([matches[4] intValue] * 256) + ([matches[5] intValue]);
}


if(port != 0 && ip != nil) {
    struct sockaddr_in servaddr_pasv;
    memset(&servaddr_pasv, 0, sizeof(servaddr_pasv));
    int isocket_pasv = socket(AF_INET,SOCK_STREAM,0);
    servaddr_pasv.sin_family = AF_INET;
    servaddr_pasv.sin_addr.s_addr = inet_addr([ip UTF8String]);
    servaddr_pasv.sin_port = htons(port);
    int res_pasv =  connect(isocket_pasv, (struct sockaddr_in *)&servaddr_pasv, sizeof(servaddr_pasv));



    if(res_pasv < 0) {
        NSLog(@"problem connecting to server passv");
    }

    NSInputStream *input = [NSInputStream inputStreamWithFileAtPath:@"/Users/myMac/Desktop/limitation.jpeg"];
    [input open];
    int i= 0;
    while(1) {
        if([input hasBytesAvailable]) {
            i++;
            uint8_t buffer[1024];
            long res = [input read:buffer maxLength:1024];
            NSLog(@"Bytes Read: %ld",res);

            if(res != 0) {
                long bytesSent = write(isocket_pasv, buffer, sizeof(buffer));
                NSLog(@"%d Bytes Transfered: %ld",i,bytesSent);
                // sleep(1);
            }
            if(res == 0) {
                break;
            }
        }
    }

    [input close];
    NSLog(@"bytes write completed");
    close(isocket_pasv);
}
close(isocket);

任何帮助提前致谢。

2 个答案:

答案 0 :(得分:4)

您无法保证可以一次性卸载整个缓冲区。在转移所有数据之前,您必须循环写入。您还应检查write返回的错误,它可能是您捕获各种网络相关事件以及更典型的O / S写入错误的地方。

答案 1 :(得分:3)

我猜这是write来电并不发送你要求它发送的全部内容?这实际上并不出人意料。您只需在新呼叫中将剩余数据发送到write

如果要编写所有数据,请使用以下内容:

int write_all(int fd, const void *buffer, const size_t bufsize)
{
    size_t to_write = bufsize;
    const void *ptr = buffer;

    while (to_write > 0)
    {
        ssize_t written = write(fd, ptr, to_write);
        if (written < 0)
            return -1;

        to_write -= written;
        ptr = ((char *) ptr) + written;
    }

    return bufsize;
}

警告:我从内存中写下以下内容,尚未对其进行测试。