在之前的文章中,实现了一个从客户端发送字符串数据到服务器的Socket程序。但是在实际应用中,往往需要通过Socket传输其他复杂一点的数据,例如struct结构或者uint8_t数组等等。

之前我尝试了直接将uint8_t数组从socket发送,但是服务端只是收到了0x00数据。后来在网上找了一些资料,终于找到了这篇文章:Linux C Socket编程发送结构体、文件详解及实例 , 按照这篇文章使用memcpy()函数将要发送的数据放入char*数组指针中。只是都是Linux的代码,我这里稍稍修改下,客户端使用Windows,服务端使用Linux

Windows客户端代码

#include <stdio.h>
#include <winsock2.h>
#include <string.h>
#include <stdlib.h>
#define PORT 3389    //服务端端口
#define BUFFER_SIZE 1024    //缓存
#define SA struct sockaddr

#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)  
#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)

#pragma comment(lib,"ws2_32.lib") //Winsock Library
#pragma warning(disable:4996)

// 定义要发送的结构体
typedef struct
{
    int ab;
    int num[100];
}Node;

int main(void)
{
    WSADATA wsa;
    SOCKET sockfd;
    struct sockaddr_in servaddr;

    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        return 1;
    }
    printf("Initialised.\n");

    // socket create and varification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("socket creation failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully created..\n");

    bzero(&servaddr, sizeof(servaddr));

    // assign IP, PORT
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr("158.101.15.187");
    servaddr.sin_port = htons(PORT);

    // connect the client socket to server socket
    if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
        printf("connection with the server failed...\n");
        exit(0);
    }
    else
        printf("connected to the server..\n");

    // send data
    
    Node* myNode = (Node*)malloc(sizeof(Node));
    myNode->ab = 123;
    myNode->num[0] = 110;
    myNode->num[99] = 99;

    int needSend = sizeof(Node);
    char* buffer = (char*)malloc(needSend);
    memcpy(buffer, myNode, needSend);

    int pos = 0;
    int len = 0;

    while (pos < needSend)
    {
        len = send(sockfd, buffer + pos, BUFFER_SIZE, 0);
        if (len <= 0)
        {
            printf("ERROR");
            break;
        }
        pos += len;
    }

    free(buffer);
    free(myNode);

    // close the socket
    closesocket(sockfd);

    WSACleanup();

    return 0;
}

Linux服务端

#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

#define PORT 3389
#define BUFFER_SIZE 1024
#define SA struct sockaddr

static void sig_handler(int sig)
{
    int retval;
    
    if ( sig == SIGCHLD )
    { 
        // 等待子程序的結束狀態
        wait(&retval);        
        printf("CATCH SIGNAL PID=%d\n",getpid());
    }
}

// 定义的结构体一定要个客户端的相同,顺序不能更改,否则接受的数据解析不正确
typedef struct
{    
    int ab;    
    int num[100];
}Node;
  
// Driver function
int main(void)
{
    int sockfd, connfd;
    struct sockaddr_in servaddr, cli;
    socklen_t len;
    pid_t pid;
  
    // socket create and verification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("socket creation failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully created..\n");
    
    bzero(&servaddr, sizeof(servaddr));
  
    // assign IP, PORT
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);
    
    int reuse = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int)) == -1)
        printf("Can't set the reuse option on the socket");
  
    // Binding newly created socket to given IP and verification
    if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
        printf("socket bind failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully binded..\n");
  
    // Now server is ready to listen and verification
    if ((listen(sockfd, 5)) != 0) {
        printf("Listen failed...\n");
        exit(0);
    }
    else
        printf("Server listening..\n");
        
    while(1)
    {
        // Accept the data packet from client and verification
        len = sizeof(cli);        
        connfd = accept(sockfd, (SA*)&cli, &len);
    
        if (connfd < 0) {
            printf("server acccept failed...\n");
            exit(0);
        }
        else
            printf("server acccept the client...\n");

        // 呼叫 signal 來接收 SIGCHLD 信號
        signal(SIGCHLD,sig_handler);
        
        pid = fork();
    
        if(pid < 0)
            printf("ERROR on fork");
        
        if(pid == 0)
        {
            close(sockfd);
            
            //recv data
            
            Node *myNode=(Node*)malloc(sizeof(Node));

            int needRecv=sizeof(Node);
            char *buffer=(char*)malloc(needRecv);
            
            int pos=0;
            int len;
            
            while(pos < needRecv)
            {
                len = recv(connfd, buffer+pos, BUFFER_SIZE, 0);
                if (len < 0)
                {
                    printf("Server Recieve Data Failed!\n");
                    break;
                }
                pos+=len; 
            }
                    
            memcpy(myNode,buffer,needRecv);
            printf("recv over ab=%d num[0]=%d num[99]=%d\n",myNode->ab,myNode->num[0],myNode->num[99]);
            free(buffer);
            free(myNode);
            
            close(connfd);
            exit(0);            
        }
        else
        {
            close(connfd);
        }
            
    }
  
    // After chatting close the socket
    close(sockfd);
    
    return 0;
}

如果是要发送uint8_t

Windows客户端

#include <stdio.h>
#include <winsock2.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#define PORT 3389
#define BUFFER_SIZE 1024
#define SA struct sockaddr

#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)  
#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)

#pragma comment(lib,"ws2_32.lib") //Winsock Library
#pragma warning(disable:4996)

typedef struct
{
    int ab;
    int num[100];
}Node;

int main(void)
{
    WSADATA wsa;
    SOCKET sockfd;
    struct sockaddr_in servaddr;

    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        return 1;
    }
    printf("Initialised.\n");

    // socket create and varification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("socket creation failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully created..\n");
    bzero(&servaddr, sizeof(servaddr));

    // assign IP, PORT
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr("158.101.15.187");
    servaddr.sin_port = htons(PORT);

    // connect the client socket to server socket
    if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
        printf("connection with the server failed...\n");
        exit(0);
    }
    else
        printf("connected to the server..\n");

    // send data
    uint8_t input_data[] = { 0x01,0x03,0x04,0x01,0xB5,0x00,0xB9,0x2B,0x9B };
    int needSend = sizeof(input_data);
    char* buffer = (char*)malloc(needSend);
    memcpy(buffer, input_data, needSend);

    int pos = 0;
    int len = 0;
    
    while (pos<needSend)
    {
        len = send(sockfd, buffer + pos, BUFFER_SIZE, 0);
        if (len <= 0)
        {
            printf("ERROR");
            break;
        }
        pos += len;
    }

    free(buffer);

    // close the socket
    closesocket(sockfd);

    WSACleanup();

    return 0;
}

Linux服务端

#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdint.h>
#define PORT 3389
#define BUFFER_SIZE 1024
#define SA struct sockaddr

static void sig_handler(int sig)
{
    int retval;
    
    if ( sig == SIGCHLD )
    { 
        // 等待子程序的結束狀態
        wait(&retval);        
        printf("CATCH SIGNAL PID=%d\n",getpid());
    }
}
  
// Driver function
int main(void)
{
    int sockfd, connfd;
    struct sockaddr_in servaddr, cli;
    socklen_t len;
    pid_t pid;
  
    // socket create and verification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("socket creation failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully created..\n");
    
    bzero(&servaddr, sizeof(servaddr));
  
    // assign IP, PORT
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);
    
    int reuse = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int)) == -1)
        printf("Can't set the reuse option on the socket");
  
    // Binding newly created socket to given IP and verification
    if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
        printf("socket bind failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully binded..\n");
  
    // Now server is ready to listen and verification
    if ((listen(sockfd, 5)) != 0) {
        printf("Listen failed...\n");
        exit(0);
    }
    else
        printf("Server listening..\n");
        
    while(1)
    {
        // Accept the data packet from client and verification
        len = sizeof(cli);        
        connfd = accept(sockfd, (SA*)&cli, &len);
        
        if (connfd < 0) {
            printf("server acccept failed...\n");
            exit(0);
        }
        else
            printf("server acccept the client...\n");

        // 呼叫 signal 來接收 SIGCHLD 信號
        signal(SIGCHLD,sig_handler);
        
        pid = fork();
    
        if(pid < 0)
            printf("ERROR on fork");
        
        if(pid == 0)
        {
            close(sockfd);
            
            //recv data
            
            uint8_t input_data[9];
            
            int needRecv = sizeof(input_data);
            char *buffer = (char*)malloc(needRecv);
            
            int pos = 0;
            int len = 0;
            
            while(pos < needRecv)
            {
                len = recv(connfd, buffer+pos, BUFFER_SIZE, 0);
                if(len < 0)
                {
                    printf("Server Recieve Data Failed!\n");
                    break;
                }
                pos+=len;
            }
            memcpy(input_data,buffer,needRecv);
            
            for(int i = 0; i < needRecv; i++)
            {
                printf("0x%02x, ", input_data[i]);
            }            
            printf("\n");            
            free(buffer);
            
            close(connfd);
            exit(0);            
        }
        else
        {
            close(connfd);
        }
            
    }
  
    // After chatting close the socket
    close(sockfd);
    
    return 0;
}

以上代码均经过测试,可以正常运行,Windows下使用 Visual Studio 2019LinuxDebian 10.10 gcc (Debian 8.3.0-6) 8.3.0

标签: none

评论已关闭