我用一对简单的客户端和服务器编写了一个程序,第一个生成一串字符串并通过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()函数来解决问题。
答案 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()
或使用errno
或strerror()
在消息中,立即,不调用任何其他系统调用。
基本上你会继续接收超过流的结尾;你在流结束或错误后打印垃圾;并且在打印邮件时忽略了实际的邮件长度。