原创 【博客大赛】socket通信的简单示例

2016-6-2 20:03 1259 17 17 分类: MCU/ 嵌入式 文集: Qt和Cpp
假设有两个进程(RoseGarden和WeatherForecast)之间需要通信,其中前者作为服务器,后者作为客户端。
这里的socket使用最常见的domain(AF_INET,即IPV4),使用的通讯类型为SOCK_STREAM。

服务器端代码如下:
#include <iostream>
#include <unistd.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <signal.h>
#include <syslog.h>
#include <arpa/inet.h>
#include <vector>
using namespace std;

int main() {
    cout << "*****************************" << endl;
    cout << "*******  RoseGarden  ********" << endl;
    cout << "*****************************" << endl;

    string hostname = "localhost.localdomain";
    string servname = "hello";

    struct addrinfo hint;
    memset(&hint, 0, sizeof(hint));
    hint.ai_flags = AI_CANONNAME;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;

    int err;
    struct addrinfo *ailist, *aip;
    if ((err = getaddrinfo(hostname.data(), servname.data(), &hint, &ailist)) != 0) {
        cerr << "<RoseGarden> Error: " << gai_strerror(err) << endl;
        exit(1);
    }
    vector<int> sockfd;
    int fd;
    for (aip = ailist; aip != NULL; aip = aip->ai_next) {
        if ((fd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) < 0)
            continue;
        if (bind(fd, aip->ai_addr, aip->ai_addrlen) < 0) {
            close(fd);
            continue;
        }
        if (listen(fd, 1) < 0) {
            close(fd);
            continue;
        }
        sockfd.push_back(fd);
        cout << "<RoseGarden> valid SOCKFD = " << fd << endl;
    }

    int clfd;
    clfd = accept(sockfd[0], NULL, NULL);
    cout << "<RoseGarden> valid CLIENT SOCKFD = " << clfd << endl;

    int count;
    string sbuf;
    while (1) {
        sbuf = "<RoseGarden> " + to_string(count++) + " message.";
        send(clfd, sbuf.data(), sbuf.size(), 0);
        sleep(1);
    }
    return 0;
}

客户端代码如下:
#include <iostream>
#include <unistd.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <signal.h>
#include <syslog.h>
#include <arpa/inet.h>
#include <vector>
using namespace std;

int main(int argc, char *argv[])
{
    cout << "*****************************" << endl;
    cout << "*****  WeatherForecast  *****" << endl;
    cout << "*****************************" << endl;

    if (argv[1] == NULL) {
        cerr << "Error: Please input address and service-name." << endl;
        exit(1);
    }
    if (argv[2] == NULL) {
        cerr << "Error: Please input service-name." << endl;
        exit(1);
    }

    struct addrinfo hint;
    memset(&hint, 0, sizeof(hint));
    hint.ai_flags = AI_CANONNAME;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;

    int err;
    struct addrinfo *ailist, *aip;
    if ((err = getaddrinfo(argv[1], argv[2], &hint, &ailist)) != 0) {
        cerr << "<WeatherForcast> Error: " << gai_strerror(err) << endl;
        exit(1);
    }
    vector<int> sockfd;
    int fd;
    for (aip = ailist; aip != NULL; aip = aip->ai_next) {
        if ((fd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) < 0)
            continue;
        if (connect(fd, aip->ai_addr, aip->ai_addrlen) != 0) {
            close(fd);
            continue;
        }
        sockfd.push_back(fd);
        cout << "<WeatherForcast> valid SOCKFD = " << fd << endl;
    }

    char rbuf[128];
    int n;
    while (1) {
        memset(rbuf, 0, sizeof(rbuf));
        n = recv(sockfd[0], rbuf, sizeof(rbuf), 0);
        if (n > 0)
            cout << "<WeatherForcase> R: " << rbuf << endl;
    }
    return 0;
}

客户端执行结果:
$ ./RoseGarden
*****************************
*******  RoseGarden  ********
*****************************
<RoseGarden> valid SOCKFD = 3
<RoseGarden> valid CLIENT SOCKFD = 4

服务器端执行结果:
$ ./WeatherForecast 127.0.0.1 hello
*****************************
*****  WeatherForecast  *****
*****************************
<WeatherForcast> valid SOCKFD = 3
<WeatherForcase> R: <RoseGarden> 0 message.
<WeatherForcase> R: <RoseGarden> 1 message.
<WeatherForcase> R: <RoseGarden> 2 message.
<WeatherForcase> R: <RoseGarden> 3 message.
<WeatherForcase> R: <RoseGarden> 4 message.
<WeatherForcase> R: <RoseGarden> 5 message.

虽然socket的原理很复杂,它使用起来却很简单。
《Unix环境高级编程》这本书的第16章讲的就是socket的用法。
刚开始看的时候,可能会被很多数量的结构体和函数绕晕了,但是没关系,看第二遍的时候就会清晰很多。
ps:多实验代码,将结构体的值打印出来观察~

文章评论0条评论)

登录后参与讨论
我要评论
0
17
关闭 站长推荐上一条 /2 下一条