python

しょっちゅう忘れることを書いておく。

33

831 views

C言語のソケットプログラムからpythonの関数をコールバックする

C言語のソケットプログラム

C言語のサンプル

#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>

#define MAX_CHILD 20
typedef void (*RECV_CALLBACK)(char *);

int serverSocket(int portno) {
    int soc, opt;
    int ret = 0;
    struct servent *se;
    struct sockaddr_in my;

    memset((char *)&my, 0, sizeof(my));
    my.sin_family = AF_INET;
    my.sin_addr.s_addr = htonl(INADDR_ANY);
    my.sin_port = htons(portno);

    /* ソケット作成 */
    soc = socket(AF_INET, SOCK_STREAM, 0);
    if(soc < 0) {
        perror("socket");
        return -1;
    }

    /* オプション設定 */
    ret = setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
    if(ret != 0) {
        perror("setsockopt");
        close(soc);
        return -1;
    }

    /* バインド */
    ret = bind(soc, (struct sockaddr *)&my, sizeof(my));
    if(ret == -1) {
        perror("bind");
        close(soc);
        return -1;
    }

    /* バックログ */
    ret = listen(soc, SOMAXCONN);
    if(ret == -1){
        perror("listen");
        close(soc);
        return -1;
    }

    return soc;
}

int RecvSendOne(int acc, int child_no, RECV_CALLBACK callBack) {
    char buf[512], *ptr;
    int len;

    if((len = recv(acc, buf, sizeof(buf), 0)) < 0) {
        perror("recv");
        return -1;
    }

    if(len==0) {
        fprintf(stderr, "[child[%d] recv: EOF\n", child_no);
        return 0;
    }

    /* 文字列化・表示 */
    buf[len] = '\0';
    /* コールバックを呼び出す */
    callBack(buf);

    if((ptr=strpbrk(buf, "\r\n")) != NULL) {
        *ptr = '\0';
    }
    fprintf(stderr, "[child%d]%s\n", child_no, buf);
    strcat(buf, ":OK\r\n");
    len = strlen(buf);
    if((len = send(acc, buf, len, 0)) < 0) {
        perror("send");
        return -1;
    }
    return 1;
}

int acceptLoop(int soc, RECV_CALLBACK callBack) {
    int acc ,len;
    struct sockaddr_in from;
    int child[MAX_CHILD];
    int child_no;
    fd_set mask;
    int width;
    struct timeval timeout;
    int i, count, pos, ret;

    for(i = 0; i < MAX_CHILD; i++) {
        child[i] = -1;
    }

    child_no = 0;

    while(1) {
        FD_ZERO(&mask);
        FD_SET(soc, &mask);
        width = soc + 1;
        count = 0;

        for(i = 0; i < child_no;i++) {
            if(child[i] != -1) {
                FD_SET(child[i], &mask);
                if(child[i] + 1 > width) {
                    width = child[i] + 1;
                    count++;
                }
            }
        } 

        timeout.tv_sec = 10;
        timeout.tv_usec = 0;

        switch(select(width, (fd_set *)&mask, NULL, NULL, &timeout)) {
            case -1:
            perror("select");
            return -1;

            case 0:
            /* タイムアウト */
            break;
            default:
            if(FD_ISSET(soc, &mask)) {
                len = sizeof(from);
                /* 接続受付 */
                acc = accept(soc, (struct sockaddr *)&from, &len);
                if(acc < 0) {
                    if(errno != EINTR) {
                        perror("accept");
                    }
                }
                else {
                    fprintf(stderr, "accept:%s:%d\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port));
                    pos = -1;
                    for(i=0; i < child_no;i++) {
                        if(child[i] == -1) {
                            pos = i;
                            break;
                        }
                    }

                    if(pos == -1) {
                        /* 空きがない */
                        if(child_no+1>=MAX_CHILD){
                            fprintf(stderr, "child is full: cannot accept\n");
                            close(acc);
                        }
                        else {
                            child_no++;
                            pos = child_no - 1;
                        }
                    }

                    if(pos != -1){
                        child[pos] = acc;
                    }
                }
            }

            /* アクセプトしたソケットがレディ */
            for(i = 0; i < child_no;i++) {
                if(child[i]  != -1) {
                    if(FD_ISSET(child[i], &mask)) {
                        ret = RecvSendOne(child[i], i, callBack);
                        if(ret <= 0) {
                            close(child[i]);
                            child[i] = -1;
                        }
                    }
                }
            }
        }
    }
    return 0;
}

void mainLoop(int port,  RECV_CALLBACK callBack) {
    int soc;
    soc = serverSocket(port);
    if(soc == -1) {
        fprintf(stderr, "serverSocker (%d): error\n", port);
    }

    fprintf(stderr,"ready for accept\n");

    acceptLoop(soc, callBack);

    close(soc);

}

ライブラリを作成

gcc -shared -fPIC -o server.so main.c

pythonから呼び出し

# coding:UTF-8
import ctypes

def recv_callback(msg):
    print(msg.decode("utf-8"))

if __name__ == '__main__':
    libsv = ctypes.CDLL("./server.so")
    cfun = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
    libsv.mainLoop.restype = None
    libsv.mainLoop.argtypes = (ctypes.c_int32,  cfun)
    libsv.mainLoop(22222, cfun(recv_callback))

Page 20 of 56.

前のページ 次のページ



[添付ファイル]


お問い合わせ

プロフィール

マッスル

自己紹介

本サイトの作成者。
趣味:プログラム/水耕栽培/仮想通貨/激辛好き
プログラムは趣味と勉強を兼ねて、のんびり本サイトを作っています。
フレームワークはdjango。
仮想通貨はNEMが好き。
水耕栽培は激辛好きが高じて、キャロライナ・リーパーの栽培にチャレンジ中。

サイト/ブログ

https://www.osumoi-stdio.com/pyarticle/

ツイッター

@darkimpact0626