Unix域套接字C服务器和Python客户端

时间:2016-04-17 11:29:40

标签: python c sockets unix client-server

我需要合并客户端和服务器代码。在这方面,我将非常感谢你的帮助。我在组合Python中共享C服务器和客户端代码。错误的葡萄柚可以在底线找到。

C服务器代码

#include <unistd.h>
#include <stdio.h>      // standard input / output functions
#include <stdlib.h>
#include <string.h>     // string function definitions
#include <fcntl.h>      // File control definitions
#include <errno.h>      // Error number definitions
#include <termios.h>    // POSIX terminal control definitions
#include <time.h>
#include <stdint.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include "list.h"
#include "pack.h"


#define SOCK_PATH "../sockets/socketNodeServer"
#define DEBUG_FILE "./debug.txt"

#pragma pack(1)

// Structure definitions
typedef struct serialRx_s{
    list* llistScatteredRx;
    list* llistOrderedRx;
    uint8_t scratchpad[SCRATCHPAD_SIZE];
    uint8_t remaining;
    uint16_t lostPackets;
    uint16_t receivedPackets;
    int fd;
}serialRx_t;

typedef struct serialTx_s{
    list* llistTx;
    uint16_t sentPackets;
    int fd;
}serialTx_t;

typedef struct monitor_s{
    struct serialRx_s *rx_p;
    struct serialTx_s *tx_p;
    FILE *fp;
}monitor_t;
#pragma pack()

// Public function prototypes

// Private function prototypes

static void *rxSerial_f(void *arg);
static void *txSerial_f(void *arg);
static void *log_f(void *arg);
static void *monitor_f(void *arg);
static int orderScattered_rxData(struct serialRx_s *rx);
static int fillupScratchpad(struct serialRx_s *rx);
static void freeNode(void *data);
static void *prep_TxGoodies(int fd);
static void *prep_RxGoodies(int fd);
static void *prep_monitoring(struct serialRx_s *rx, struct serialTx_s *tx);
static void set_blocking (int fd, int should_block);
static int set_interface_attribs (int fd, int speed, int parity);
static void *form_node_data_packet(void *buf, int len);
static int setNonBlocking(int fd);



static int set_interface_attribs (int fd, int speed, int parity)
{
    struct termios tty;
    memset (&tty, 0, sizeof tty);
    if (tcgetattr (fd, &tty) != 0)
    {
        printf ("error %d from tcgetattr", errno);
        return -1;
    }

    cfsetospeed (&tty, speed);
    cfsetispeed (&tty, speed);

    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
    // disable IGNBRK for mismatched speed tests; otherwise receive break
    // as \000 chars
    tty.c_iflag &= ~IGNBRK;         // disable break processing
    tty.c_lflag = 0;                // no signaling chars, no echo,
    // no canonical processing
    tty.c_oflag = 0;                // no remapping, no delays

    // For details about blocking in non canonical (binary mode)
    // check out http://www.tldp.org/HOWTO/html_single/Serial-HOWTO/
    tty.c_cc[VMIN]  = 0;            // read doesn't block
    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

    tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

    tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
    // enable reading
    tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
    tty.c_cflag |= parity;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;

    if (tcsetattr (fd, TCSANOW, &tty) != 0)
    {
        printf ("error %d from tcsetattr", errno);
        return -1;
    }
    return 0;
}

static void set_blocking (int fd, int should_block)
{
    struct termios tty;
    memset (&tty, 0, sizeof tty);
    if (tcgetattr (fd, &tty) != 0)
    {
        printf ("error %d from tggetattr", errno);
        return;
    }

    tty.c_cc[VMIN]  = should_block ? 1 : 0;
    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

    if (tcsetattr (fd, TCSANOW, &tty) != 0)
        printf ("error %d setting term attributes", errno);
}


static void * prep_monitoring(struct serialRx_s *rx, struct serialTx_s *tx)
{
    struct monitor_s *monitor_p = NULL;

    monitor_p = (struct monitor_s *)malloc(sizeof(struct monitor_s));
    if(NULL == monitor_p){
        return NULL;
    }
    monitor_p->rx_p = rx;
    monitor_p->tx_p = tx;
    monitor_p->fp = fopen(DEBUG_FILE, "w+");

    return monitor_p;
}

static void *prep_RxGoodies(int fd)
{
    struct serialRx_s *rx = NULL;

    rx = (struct serialRx_s *)malloc(sizeof(struct serialRx_s));

    rx->llistScatteredRx = create_list();
    rx->llistOrderedRx = create_list();
    rx->fd = fd;
    memset(rx->scratchpad, 0, sizeof(rx->scratchpad));
    rx->remaining       = 0;
    rx->lostPackets     = 0;
    rx->receivedPackets = 0;

    return rx;
}

static void *prep_TxGoodies(int fd)
{
    struct serialTx_s *tx = NULL;

    tx = (struct serialTx_s *)malloc(sizeof(struct serialTx_s));

    tx->llistTx = create_list();
    tx->fd = fd;
    tx->sentPackets = 0;
    return tx;
}

static void freeNode(void *data)
{
    free( (uint8_t *)data);
}

static int fillupScratchpad(struct serialRx_s *rx)
{
    int targetNodeIndex = -1;
    int nodeLen = 0;
    uint8_t *nodeData = NULL;
    int offset = 0;
    uint8_t *pointer = NULL;

    targetNodeIndex = payloadLen_2_index(rx->llistScatteredRx, PACKET_SIZE - rx->remaining);
    //printf("targetNodeIndex value %d\n", targetNodeIndex);

    for(int i=0; i <= targetNodeIndex ; i++){
        offset = rx->remaining;
        pointer = (uint8_t *)front(rx->llistScatteredRx); // first byte is for length
        nodeLen = pointer[0];
        //nodeLen = ((uint8_t *)front(rx->llistScatteredRx))[0]; // first byte is for length
        //printf("nodeLen in fillupScratchpad %d\n", nodeLen);
        nodeData = (uint8_t *)front(rx->llistScatteredRx) + 1; // first byte is for length
        memcpy(rx->scratchpad + offset, nodeData, nodeLen); 
        rx->remaining += nodeLen;
        //for(int j=0; j<rx->remaining; j++)
        //{
        //    printf("scratchpad[%d]: %X\n", j, (rx->scratchpad)[j]);
        //}
        remove_front(rx->llistScatteredRx, freeNode);
    }
    return targetNodeIndex;
}

static int orderScattered_rxData(struct serialRx_s *rx)
{
    int packetBeginIndex = 0;
    struct raw_node_data_s *raw = NULL;

    // parse the scratchpad buffer until the last remaining byte
    // note that since we have a larger buffer size than what we use
    // it's safe to do this.
    for(int i=0; i < (rx->remaining) ; i++)
    {
        // Check whether we have a suitable package
        if(rx->scratchpad[i]               == START_CODE && 
           rx->scratchpad[i+PACKET_SIZE-1] == STOP_CODE)
        {
            //printf("start & stop matches\n");
            raw = (struct raw_node_data_s *)malloc(sizeof(struct raw_node_data_s));
            memcpy(raw, rx->scratchpad + i, sizeof(struct raw_node_data_s));
            //print_raw_node_data(raw);
            push_back(rx->llistOrderedRx, raw);
            rx->receivedPackets++;
            //TODO: Check for CRC

            // clear up memory area between beginning of scratchpad and Stop_Code
            memset(rx->scratchpad, 0, i+PACKET_SIZE-1);

            // move remaining bytes to the beginning of scratchpad buffer
            // no overlapping should occur but still, use memmove instead of memcpy
            memmove(rx->scratchpad,                         
                    rx->scratchpad + i + PACKET_SIZE,  // point to right after the healthy packet
                    rx->remaining - ( i + PACKET_SIZE));   // get remaining bytes after packet end

            // update remaining bytes value
            rx->remaining = rx->remaining - (i + PACKET_SIZE);
            packetBeginIndex = i;  // success
            break;
        }
    }

    //  if no packets can be formed, check whether we are running out of
    //  scratchpad buffer, clear up memory if this is the case. Make sure
    //  to increase packet lost counter
    //if( !packetBeginIndex && (rx->remaining >= 2 * PACKET_SIZE) )
    if( (rx->remaining >= (3 * PACKET_SIZE)) )
    {

        printf("we are running out of space\n");
        printf("scratchpad size: %d\n", rx->remaining);
        for(int i=0; i < (rx->remaining) ; i++)
        {
            if(rx->scratchpad[i] == START_CODE){ 

                // clear up the first packet area and move up the 
                // remaining bytes to the beginning of buffer
                memset(rx->scratchpad, 0, i-1);
                memmove(rx->scratchpad, 
                        rx->scratchpad + i,
                        rx->remaining  - i   );

                rx->remaining -= i;
                rx->lostPackets += 1;
            }
        }
    }

    // don't care for START_CODE, clear up an area 
    // big enough to hold a full packet
    if((rx->remaining >= 3 * PACKET_SIZE)){

        printf("buffer is a complete mess, clear up stuff\n");
        // buffer is a complete mess, 
        // clear up a whole packet
        memset(rx->scratchpad, 0, PACKET_SIZE);
        memmove(rx->scratchpad, 
                rx->scratchpad + PACKET_SIZE+1,
                rx->remaining - PACKET_SIZE);

        rx->remaining -= PACKET_SIZE;
        rx->lostPackets += 1;
    }


    //for(int j=0; j<rx->remaining; j++)
    //{
    //    printf("scratchpad after cleanup[%d]: %X\n", j, (rx->scratchpad)[j]);
    //}
    return packetBeginIndex;
}

static void *txSerial_f(void *arg)
{
    struct serialTx_s *tx = (struct serialTx_s *)arg;
    struct raw_node_data_s *txRaw = NULL;
    int n = 0;

    //txRaw = prep_transaction_data();
    //print_raw_node_data(txRaw);

    sleep(1);

    while(1)
    {
        //n =  write(tx->fd, txRaw, sizeof(txRaw));
        if(size(tx->llistTx)){
            txRaw = front(tx->llistTx);
            n =  write(tx->fd, txRaw, PACKET_SIZE);
            //printf("sending %d bytes via serial \n", n);
            remove_front(tx->llistTx, freeNode);
            tx->sentPackets += 1;
        }
        sleep(1);
    }

    return NULL;
}

static void *form_node_data_packet(void *buf, int len)
{
    struct raw_node_data_s *raw = NULL;

    raw = (struct raw_node_data_s *)malloc(sizeof(struct raw_node_data_s));
    if(!raw){
        fprintf(stderr,"can't allocate memory for raw node\n");
        return NULL;
    }

    memcpy(raw, buf, len);
    //print_raw_node_data(raw);

    return raw;
}

//TODO: Move this function to a new source file for socket operations
static int setNonBlocking(int fd)
{
  int flags;


/* if O_NONBLOCK is defined, use the fcntl function */
  if(-1 == (flags = fcntl(fd, F_GETFL, 0))){
    flags = 0;
  }

  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

static void *monitor_f(void *arg)
{
    struct monitor_s *mon = (struct monitor_s *)arg;
    struct raw_node_data_s *txRaw = NULL;
    uint8_t rxbuf[100];

    // socket operation related variables
    int fdBind, fdAccept;
    int t, len, status;
    struct sockaddr_un local;
    struct sockaddr_un remote;


    if(-1 == (fdBind = socket(AF_UNIX, SOCK_STREAM, 0)))
    {
        fprintf(stderr, "can't open socket: %s\n", strerror(errno));
        return (void *)NULL;
    }

    local.sun_family = AF_UNIX;
    strcpy(local.sun_path, SOCK_PATH);
    unlink(local.sun_path);
    len = strlen(local.sun_path) + sizeof(local.sun_family);

    if( bind(fdBind, (struct sockaddr *)&local, len) == -1){
        fprintf(stderr, "can't bind: %s\n", strerror(errno));
        return (void *)NULL;
    }

    if(-1 == listen(fdBind, 5)){ // number of listenes can actually be less
        fprintf(stderr, "can't listen: %s\n", strerror(errno));
        return (void *)NULL;
    }

    for(;;){

        socklen_t size = sizeof(remote);
        int rcvdBytes = 0;

        fprintf(stderr, "waiting for a connection\n");

        if( -1 == (fdAccept = accept(fdBind, (struct sockaddr *)&remote, &size)) )
        {
            fprintf(stderr, "can't accept: %s\n", strerror(errno));
            return (void *)NULL;
        }
        //setNonBlocking(fdAccept);
        status = 1;
    printf("connected\n");
        do{

            if( (t = recv(fdAccept, rxbuf, 100, 0)) > 0){
                fprintf(stderr, "incoming bytes len from server: %d\n", t);
                for(int ii=0; ii < t; ii++){
                    printf("incoming data[%i]:%X\n", ii, rxbuf[ii]);
                }
                txRaw = (struct raw_node_data_s *)form_node_data_packet(rxbuf, t);
                push_back(mon->tx_p->llistTx, txRaw);
            }else if(t < 0){
                perror("recv");  // if nonblocking then wouldhaveblocked would come here too
            }else{
                fprintf(stderr, "server closed connection\n");
                status = 0;
            }

            usleep(200);


        }while(status);

        sleep(2);
        close(fdBind);

    } // while(1), thread start

    return NULL;
}


static void *log_f(void *arg)
{
    struct monitor_s *log = (struct monitor_s *)arg;
    struct raw_node_data_s *rxRaw = NULL;

    while(1)
    {
        if( size(log->rx_p->llistOrderedRx)){
            rxRaw = front(log->rx_p->llistOrderedRx);

            printf("log thread\n");
            print_raw_node_data(rxRaw);
            remove_front(log->rx_p->llistOrderedRx, freeNode);

          //fprintf(mon->fp, "\rSent Packets: %d", i);
            fprintf(log->fp, "Sent Packets: %d\n", log->tx_p->sentPackets);
            fprintf(log->fp, "Received Packets: %d\n", log->rx_p->receivedPackets);
            fprintf(log->fp, "Dropped Packets: %d\n", log->rx_p->lostPackets);
            fflush(log->fp);
            sleep(1);
        }
    } // while (1)

    return NULL;

}

static void *rxSerial_f(void *arg)
{
    struct serialRx_s *rx = (struct serialRx_s *)arg;
    int n = 0;
    uint8_t buf[100] = {0}; 
    uint8_t *dataPack = NULL;

    tcflush(rx->fd, TCIFLUSH); /* Discards old data in the rx buffer */

    while(1)
    {
        n = read(rx->fd, (uint8_t *)buf, sizeof(struct raw_node_data_s));
        //for(int ii=0; ii < n; ii++){
        //    printf("incoming serial data[%i]:%X\n", ii, ((uint8_t *)buf)[ii]);
        //}

        if(n > 0){
            //printf("read %d bytes\n", n);
            dataPack = (uint8_t *)malloc(sizeof(uint8_t)* n);
            dataPack[0] = n;
            memcpy(dataPack + 1, buf, sizeof(uint8_t)*n);
            push_back(rx->llistScatteredRx, dataPack);
            //printf("linked list size after read: %d\n", size(rx->llistScatteredRx));
            //for(int i=0; i<n; i++)
            //{
            //    printf("read data[%d]: %X\n", i, dataPack[i+1]);
            //}
            dataPack = NULL;
            memset(buf, 0, sizeof(buf));  // clear up 

            // Check whether we have enough data in the
            // scratchpad to forma packet
            fillupScratchpad(rx);
            orderScattered_rxData(rx);

        }else if(n < 0){
            printf("error in read operation\n");
        }else{
            //printf("no data - rx\n");
        }

        sleep(1);

    } // while(1)

    return NULL;
} //void *rxSerial_f(void *arg)



// *************************************************
// *************************************************
// *************************************************

// **************    TODO  *************************
// * Have thread functions in seperate files
// * Implement CRC check mechanism
// * Implement DAC switch mechanism
// * Implement for loop on writes to Serial Device
//   to make sure that all data is sent on the tx line
int main(void)
{
    pthread_t idThreadSerial[2]; // wr, rd

    char *portname = "/dev/ttyS2";

    struct serialRx_s *serialRx_p = NULL;
    struct serialTx_s *serialTx_p = NULL;
    struct monitor_s  *monitor_p  = NULL;

    srand(time(NULL));  // generate seed data for random()
    printf("size of raw_node_data_s structure: %ld\n", sizeof(struct raw_node_data_s));

    int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
    set_interface_attribs (fd, B38400, 0);  // set speed to 38400 bps, 8n1 (no parity)
    //set_blocking (fd, 0);                // set no blocking

    serialTx_p = (struct serialTx_s *)prep_TxGoodies(fd);
    serialRx_p = (struct serialRx_s *)prep_RxGoodies(fd);
    monitor_p  = (struct monitor_s  *)prep_monitoring(serialRx_p, serialTx_p);

    fwrite ("hello!\n", sizeof(uint8_t), 7, stdout);
    sleep(1);

    pthread_create(&idThreadSerial[3], NULL, log_f,      (void *)monitor_p);
    pthread_create(&idThreadSerial[2], NULL, monitor_f,  (void *)monitor_p);
    //pthread_create(&idThreadSerial[1], NULL, rxSerial_f, (void *)serialRx_p);
    //pthread_create(&idThreadSerial[0], NULL, txSerial_f, (void *)serialTx_p);

    pthread_join(idThreadSerial[0], NULL);
    pthread_join(idThreadSerial[1], NULL);
    pthread_join(idThreadSerial[2], NULL);
    pthread_join(idThreadSerial[3], NULL);
    fwrite("all threads returned, exiting now...\n", sizeof(uint8_t), 40, stdout);
    return 0;

}

Python客户端代码

# -*- coding: utf-8 -*-
import socket
import os, os.path

print "Connecting..."
if os.path.exists( "../sockets/socketNodeServer" ):
  client = socket.socket( socket.AF_UNIX, socket.SOCK_DGRAM )
  client.connect( "../sockets/socketNodeServer" )
  print "Ready."
  print "Ctrl-C to quit."
  print "Sending 'DONE' shuts down the server and quits."
  while True:
    try:
      x = raw_input( "> " )
      if "" != x:
        print "SEND:", x
        client.send( x )
        if "DONE" == x:
          print "Shutting down."
          break
    except KeyboardInterrupt, k:
      print "Shutting down."
  client.close()
else:
  print "Couldn't Connect!"
print "Done

&#34;

错误

Connecting...
Traceback (most recent call last):
  File "client.py", line 8, in <module>
    client.connect( "../sockets/socketNodeServer" )
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 91] Protocol wrong type for socket

1 个答案:

答案 0 :(得分:0)

在您的C代码中,您可以创建一个流

fdBind = socket(AF_UNIX, SOCK_STREAM, 0)

并在Python中有一个数据报:

client = socket.socket( socket.AF_UNIX, socket.SOCK_DGRAM )

当然,这是套接字的错误类型。在两边使用相同的STREAMDGRAM