C++ Socket(五)

recvmsg()/sendmsg()函数是socket编程中最常用的函数。其他IO函数能实现的一切功能recvmsg()/sendmsg()都可实现,下面是一个简单的例子

服务端

#include <iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<signal.h>
#include<string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include<stdlib.h>
#include<stdio.h>

using namespace std;

void do_SIGINT(int param);
void do_SIGPIPE(int param);
void handler_client(int _client_fd);

const static int PORT = 8888;
const static int WAITING=5;
const static int MSG_NUM=3;
const static int MSG_SIZE=10;

int server_fd;

int main()
{
    signal(SIGINT,do_SIGINT);
    signal(SIGPIPE,do_SIGPIPE);

    server_fd=socket(AF_INET,SOCK_STREAM,0);
    if(server_fd<0){
        cout<<"socket error\n";
        return -1;
    }

    sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    server_addr.sin_port=htons(PORT);

    int err=bind(server_fd,(sockaddr*)&server_addr,sizeof(server_addr));
    if(err<0){
        cout<<"bind error\n";
        return -1;
    }

    err=listen(server_fd,WAITING);
    if(err<0){
        cout<<"listen error\n";
        return -1;
    }

    int client_fd;
    sockaddr_in client_addr;
    socklen_t len=sizeof(sockaddr);
    bzero(&client_addr,sizeof(client_addr));
    int pid=-1;
    while(true){
        if(pid==0)
            break;
        cout<<"wait for new client"<<endl;
        client_fd=accept(server_fd,(sockaddr*)&client_addr,&len);
        if(client_fd<0){
            cout<<server_fd<<endl;
            perror("client conn fail\n");
            continue;
        }

        pid=fork();
        if(pid==-1){
            close(client_fd);
            cout<<"client conn fail\n";
            continue;
        }
        if(pid==0){
            close(server_fd);
            cout<<"sub prog handler client fd\n";
            handler_client(client_fd);
        }else{
            close(client_fd);
            cout<<"main prog close client fd\n";
        }
    }

}

void do_SIGINT(int sig){
    cout<<"catch a SIGINT\n";
    close(server_fd);
    _exit(0);
}

void do_SIGPIPE(int sig){
    cout<<"catch a SIGPIPE\n";
}

void handler_client(int _client_fd){

    msghdr msg;
    //由于在TCP持有连接状态的,所以连接两端的地址和端口都很明确,故这两个参数不生效
    //但是由于UDP是无连接状态的,所以这两个参数将在UDP连接中有效
    msg.msg_name=NULL;
    msg.msg_namelen=0;
    msg.msg_control=NULL;
    msg.msg_controllen=0;
    msg.msg_iov=NULL;
    msg.msg_iovlen=30;
    msg.msg_flags=0;
    msg.msg_iov=(iovec *)malloc(MSG_NUM*sizeof(iovec));
    int i;
    for(i=0;i<MSG_NUM;i++){
        msg.msg_iov[i].iov_base=(char*)malloc(MSG_SIZE);
        msg.msg_iov[i].iov_len=MSG_SIZE;
    }


    int size;
    char* output;
    while(true){
        size=recvmsg(_client_fd,&msg,0);
        if(size<1)
        {
            if(size==0)
                close(_client_fd);
            break;
        }
        cout<<"rec size is "<<size<<endl;
        cout<<"------------------------start"<<endl;
        for(i=0;i<MSG_NUM;i++){
            cout<<"------------------------>"<<endl;
            cout<<"msg length is "<<msg.msg_iov[i].iov_len<<endl;
            output=(char*)malloc(msg.msg_iov[i].iov_len+1);
            bzero(output,msg.msg_iov[i].iov_len+1);
            memcpy(output,msg.msg_iov[i].iov_base,msg.msg_iov[i].iov_len);
            cout<<output<<"|"<<endl;
            free(output);
            cout<<"<------------------------"<<endl;
        }
        cout<<"------------------------end"<<endl;
    }
    for(i=0;i<MSG_NUM;i++){
        free( msg.msg_iov[i].iov_base);
    }
    free(msg.msg_iov);
    free(msg.msg_name);
}

客户端

#include <iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<signal.h>
#include<string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include<stdlib.h>
#include<stdio.h>

using namespace std;

const static int PORT = 8888;
const static int MSG_NUM=3;
const static int MSG_SIZE=10;
const static string SERVER_IP="192.168.163.143";

void do_SIGINT(int param);
void do_SIGPIPE(int param);
void do_client(int _server_fd);

int from_server_fd;

int main()
{
    signal(SIGINT,do_SIGINT);
    signal(SIGPIPE,do_SIGPIPE);

    from_server_fd=socket(AF_INET,SOCK_STREAM,0);
    if(from_server_fd<0){
        cout<<"socket error\n";
        return -1;
    }

    sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    //server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    server_addr.sin_addr.s_addr=inet_addr(SERVER_IP.c_str());
    server_addr.sin_port=htons(PORT);
    connect(from_server_fd,(sockaddr*)&server_addr,sizeof(sockaddr));
    do_client(from_server_fd);
    close(from_server_fd);
}

void do_SIGINT(int sig){
    cout<<"catch a SIGINT\n";
    close(from_server_fd);
    _exit(0);
}

void do_SIGPIPE(int sig){
    cout<<"catch a SIGPIPE\n";
}

void do_client(int _server_fd){

    msghdr msg;
    //由于在TCP持有连接状态的,所以连接两端的地址和端口都很明确,故这两个参数不生效
    //但是由于UDP是无连接状态的,所以这两个参数将在UDP连接中有效
    msg.msg_name=NULL;
    msg.msg_namelen=0;
    msg.msg_control=NULL;
    msg.msg_controllen=0;
    msg.msg_iov=NULL;
    msg.msg_iovlen=30;
    msg.msg_flags=0;
    msg.msg_iov=(iovec *)malloc(MSG_NUM*sizeof(iovec));
    int i;
    for(i=0;i<MSG_NUM;i++){
        msg.msg_iov[i].iov_base=(char*)malloc(MSG_SIZE);
        msg.msg_iov[i].iov_len=MSG_SIZE;
    }
    while(true){
        for(i=0;i<MSG_NUM;i++){
            string input;
            cin>>input;
            cout<<"input is "<<input<<" length is "<<input.size()<<endl;
            memcpy(msg.msg_iov[i].iov_base,input.c_str(),input.size());
            msg.msg_iov[i].iov_len=input.size();
        }

        sendmsg(_server_fd,&msg,0);
    }
    free(msg.msg_iov);
    free(msg.msg_name);
}


运行结果


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值