sendmsg()没有按预期运行

时间:2015-07-09 01:29:39

标签: sockets unix

我用一对简单的客户端和服务器编写了一个程序,第一个生成一串字符串并通过socket提供的API发送它们,即sendmsg(),第二个接收字符串,方便epoll的。

根据tcpdump捕获的内容和客户端执行的结果,客户端能够连接到服务器并正确发送一些消息,但只有少数消息,以下字符串无法完全接收,并且在接收到的代码的服务器打印结束时,存在相同字符串段的无限重复。

如果需要更多细节,请与我联系。

顺便说一句,是否有任何推荐参考资料提供有关sendmsg()用法的详细说明?

这是客户的主要代码:

void MultithreadedLogAnalyzer::SendToServer(string Addr,uint16_t Port) {
    int connfd = socket(AF_INET,SOCK_STREAM,0);
    sockaddr_in servaddr;

    servaddr.sin_family = AF_INET;

    servaddr.sin_port = htons(Port);
    inet_pton(AF_INET,Addr.c_str(),&servaddr.sin_addr);

    /*connect failure process to be added*/

    int st = connect(connfd,(struct sockaddr *)&servaddr,sizeof(sockaddr));
    if(-1 == st){
        perror("connection failed");
    }   
    Handle(connfd,servaddr);

    close(connfd);

}

void MultithreadedLogAnalyzer::Handle(int connfd,const sockaddr_in &servaddr){
  int n= 0,counter =0;
  for(vector<string>::iterator si = mFilterResult.begin();si != mFilterResult.end(); ++si)
  {   
      msghdr msg;
      iovec iov;
      memset(&msg,0,sizeof(msg));
      memset(&iov,0,sizeof(iov));
      msg.msg_control = NULL;
      msg.msg_controllen = 0;
      msg.msg_flags = 0;
      char data[1024];
      memset(data,0, 1024);
      memcpy(data,si->c_str(),si->size());
      iov.iov_base = data;
      iov.iov_len = (*si).size() ;//check first to locate error
      cout << "size:" << (*si).size() << endl;
      msg.msg_name = NULL;
      msg.msg_namelen = 0;
      msg.msg_iov = &iov;
      msg.msg_iovlen = 1;
      //msg.msg_accrights = NULL;
      //msg.msg_accrightslen = 0; 
      n = sendmsg(connfd,&msg,0);
      cout << "n: " <<  n << endl;
      ++counter;
      if (-1 == n)
          perror("sendmsg error\n");
  }
  cout << "number of strings send: " << counter << endl;

服务器代码如下:

#include <sys/socket.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <strings.h>
#include <netinet/in.h>
#include <sys/epoll.h>

#define POLLSIZE  100
#define STRINGSIZE 300
using namespace std;
void handle(int fd){
int c = 0;
do{
    msghdr msg;
    memset(&msg,0,sizeof(msghdr));
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    char data[1024];
    iovec iov;
    iov.iov_base = data;
    iov.iov_len = 1024;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = NULL;
    msg.msg_controllen = 0;
    msg.msg_flags = 0;
    c = recvmsg(fd,&msg,0);
    if(msg.msg_iovlen==0
            ){
        return;
    }
        cout << "msg length:" << msg.msg_iovlen<< endl;
        cout << string((char *)(msg.msg_iov[0].iov_base)) << endl;
    }while(c != -1);
}

int main() {
    int listenfd;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in servaddr,cliaddr;
    socklen_t socklen = 0;
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

int serverPort = 2000;
servaddr.sin_port = htons(serverPort);

bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
int listennumnber = 20;
listen(listenfd,listennumnber);

//the rest to be commented
int epfd = epoll_create(POLLSIZE);
if (epfd < 0)
    perror("epoll_create");
struct epoll_event ev;
ev.events = EPOLLIN|EPOLLET;
ev.data.fd = listenfd;
if(epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev) < 0)
    perror("epoll_ctl");
int curfds  = 1;
struct epoll_event *events = (struct epoll_event*)malloc(sizeof(struct epoll_event));

for (;;){
    int n;
    int nfds = epoll_wait(epfd,events,curfds,-1);
    if (-1 == nfds)
        continue;
        for(n = 0;n < nfds; ++n){
            if(events[n].data.fd == listenfd){
                int connfd = accept(listenfd,(struct sockaddr *)&cliaddr ,&socklen);
                cout << "connect established through connfd: " << connfd << endl;
                    if (connfd < 0)
                        continue;
            //      if(setnonblocking(connfd) < 0)
            //          perror("set setnonblocking error");
                    ev.events = EPOLLIN | EPOLLET;
                    ev.data.fd = connfd;
                    if(epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev) < 0)
                        return -1;
                    curfds++;
                    continue;
            }
            handle(events[n].data.fd);
        }
}

return 0;
}

通过在邮件传输循环的适当位置添加send()和recv()函数来解决问题。

1 个答案:

答案 0 :(得分:0)

    cout << "msg length:" << msg.msg_iovlen<< endl;
    cout << string((char *)(msg.msg_iov[0].iov_base)) << endl;

此消息只应打印msg.msg_iov[0].iov_len个字节。

}while(c != -1);

这是错误的地方。它应该是在c = recvmsg(...); if (c > 0)之后立即进行的测试,如果是c == -1,您应该致电perror()或使用errnostrerror()在消息中,立即,不调用任何其他系统调用。

基本上你会继续接收超过流的结尾;你在流结束或错误后打印垃圾;并且在打印邮件时忽略了实际的邮件长度。