TCP/UDP网络编程客户端和服务器传输结构体数据代码

 一,TCP服务器和客户端代码

1,TCP服务器流程

服务器:
      (1)创建socket,使用socket函数
      (2)准备通信地址,使用结构体类型
      (3)绑定socket和通信地址,使用bind函数
      (4)进行通信,使用read/write函数
      (5)关闭socket,使用close函数
客户端:
      (1)创建socket,使用socket函数
      (2)准备通信地址,使用服务器的地址
      (3)连接socket和通信地址,使用connect函数
      (4)进行通信,使用read/write函数
      (5)关闭socket,使用close函数


2,三次握手

在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。

第一次握手,客户端向服务器端发出连接请求,等待服务器确认

第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求

第三次握手,客户端再次向服务器端发送确认信息,确认连接

4,定义结构体

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

5,服务器代码(传结构体数据)

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

#define HELLO_WORLD_SERVER_PORT    6666
#define LENGTH_OF_LISTEN_QUEUE     20
#define BUFFER_SIZE                1024

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

int main(int argc, char **argv)
{
    // set socket's address information
    struct sockaddr_in   server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);

    // create a stream socket
    int server_socket = socket(PF_INET, SOCK_STREAM, 0);
    if (server_socket < 0)
    {
        printf("Create Socket Failed!\n");
        exit(1);
    }

    //bind
    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)))
    {
        printf("Server Bind Port: %d Failed!\n", HELLO_WORLD_SERVER_PORT);
        exit(1);
    }

    // listen
    if (listen(server_socket, LENGTH_OF_LISTEN_QUEUE))
    {
        printf("Server Listen Failed!\n");
        exit(1);
    }

    while(1)
    {
        struct sockaddr_in client_addr;
        socklen_t          length = sizeof(client_addr);

        int new_server_socket = accept(server_socket, (struct sockaddr*)&client_addr, &length);
        if (new_server_socket < 0)
        {
            printf("Server Accept Failed!\n");
            break;
        }

        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(new_server_socket, buffer+pos, BUFFER_SIZE, 0);
            if (len < 0)
            {
                printf("Server Recieve Data Failed!\n");
                break;
            }
            pos+=len;

        }
        close(new_server_socket);
        memcpy(myNode,buffer,needRecv);
        printf("recv over ab=%d num[0]=%d num[1]=%d\n",myNode->ab,myNode->num[0],myNode->num[1]);
        free(buffer);
        free(myNode);
    }
    close(server_socket);

    return 0;
}

6,客户端传送结构体代码

#include <sys/types.h>
#include <sys/socket.h>                         // 包含套接字函数库
#include <stdio.h>
#include <netinet/in.h>                         // 包含AF_INET相关结构
#include <arpa/inet.h>                      // 包含AF_INET相关操作的函数
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <pthread.h>

#define MYPORT  6666
#define BUFFER_SIZE 1024

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


int transdata(int sock_cli)
{
    Node *myNode=(Node*)malloc(sizeof(Node));
    myNode->ab=123;
    myNode->num[0]=110;
    myNode->num[1]=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(sock_cli, buffer+pos, BUFFER_SIZE,0);
        if(len <= 0)
        {
            perror("ERRPR");
            break;
        }
        pos+=len;
    }
    printf("Send ed,len=%d!!!\n",len);
      sleep(1);
    free(buffer);
    free(myNode);
}
int main()
{
    int sock_cli = socket(AF_INET,SOCK_STREAM, 0);
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(MYPORT);
    servaddr.sin_addr.s_addr = inet_addr("192.168.133.128");
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }
     transdata(sock_cli);
    printf("Send over!!!\n");
    return 0;
}

二,UDP服务器和客户端代码

 1,通信模型
服务器:
     (1)创建socket,使用socket函数
     (2)准备通信地址,使用结构体类型
     (3)绑定socket和通信地址,使用bind函数
     (4)监听,使用listen函数
     (5)响应客户端的连接请求,使用accept函数
     (6)进行通信,使用read/write函数
     (7)关闭socket,使用close函数
客户端:
     (1)创建socket,使用socket函数
     (2)准备通信地址,使用服务器的地址
     (3)连接socket和通信地址,使用connect函数
     (4)进行通信,使用read/write函数
     (5)关闭socket,使用close函数

2,UDP发送和接收函数

(1),sendto函数
    #include <sys/types.h>
    #include <sys/socket.h>
     ssize_t send(int sockfd, const void *buf, size_t len, int flags);
     ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
第一个参数:socket描述符,socket函数的返回值
第二个参数:被发送数据的首地址
第三个参数:被发送数据的大小
第四个参数:发送的标志,默认给0表示产生阻塞
第五个参数:数据接受方的通信地址
第六个参数:数据接受方通信地址的大小
返回值:成功返回实际发送的数据大小,失败返回-1
函数功能:主要用于将指定的消息发送到指定的地址上,

(2),recvfrom函数
     #include <sys/types.h>
     #include <sys/socket.h>
     ssize_t recv(int sockfd, void *buf, size_t len, int flags);
     ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
第一个参数:socket描述符,socket函数的返回值
第二个参数:存放接受到数据的缓冲区首地址
第三个参数:接受的数据大小
第四个参数:接受的标志,默认给0即可
第五个参数:保存数据发送方的通信地址(来电显示)
第六个参数:通信地址的大小
返回值:成功返回实际接受的数据大小,失败返回-1
函数功能:主要用于接受指定的数据并提供来电显示的功能

3,sockaddr_in(在netinet/in.h中定义):

struct sockaddr_in
{
short sin_family;/*Address family一般来说AF_INET(地址族)PF_INET(协议族)*/
unsigned short sin_port;/*Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/
struct in_addr sin_addr;/*IP address in network byte order(Internet address)*/
unsigned char sin_zero[8];/*Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐*/
};

sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号,在linux下,端口号的范围0~65535,同时0~1024范围的端口号已经被系统使用或保留。
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址

in_addr结构

typedef uint32_t in_addr_t;

  struct in_addr
  {
    in_addr_t s_addr;
  };

4,UDP传输字符串开进程代码

(1)UDP服务器通讯普通代码

#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <netinet/in.h>
#include<arpa/inet.h>
int sockfd;
void sig_handler(int signo)
{
    if (signo == SIGINT)
    {
        printf("server close\n");
        close(sockfd);
        exit(1);
    }
}
void out_addr(struct sockaddr_in * clientaddr)
{
    char ip[16];
    int port;
    memset(ip, 0, sizeof(ip));
    inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr, ip, sizeof(ip));
    port = ntohs(clientaddr->sin_port);
    printf("client: %s(%d)\n", ip, port);
}
void do_service()
{
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(clientaddr);
    char buffer[1024];
    memset(buffer, 0, sizeof(buffer));
    //接收客户端的数据报文
    if (recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&clientaddr, &len) < 0)
    {
        perror("recvfrom error");
    }
    else
    {
        out_addr(&clientaddr);
        printf("client send into: %s \n", buffer);
        //向客户端发送数据报文
        long int t = time(0);
        char *ptr = ctime(&t);
        size_t size = strlen(ptr) * sizeof(char);
        if (sendto(sockfd, ptr, size, 0, (struct sockaddr*)&clientaddr, len) < 0)
        {
            perror("sendto error");
        }
    }
}
int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        printf("usage: %s port \n", argv[0]);
        exit(1);
    }
    if (signal(SIGINT, sig_handler) == SIG_ERR)
    {
        perror("signal sigint error");
        exit(1);
    }
    /*1.创建socket*/
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        exit(1);
    }
    int ret;
    int opt = 1;
    //设置套接字选项SO_REUSEADDR,1.保证停用的端口可以立即使用;2.在此程序不被终止的情况下,新启动的程序绑定相同的端口也会//成功,不过此程序端口会失效。
    if ((ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0)
    {
        perror("setsockopt error");
        exit(1);
    }
    /*2.调用bind函数对socket和地址进行绑定*/
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET; //IPv4
    serveraddr.sin_port = htons(atoi(argv[1]));//port
    serveraddr.sin_addr.s_addr = INADDR_ANY;//ip
    if (bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
    {
        perror("bind error");
        exit(1);
    }
    /*3.与客户端进行数据通信*/
    while (1)
    {
        do_service();
    }
    return 0;
}

(2)UDP客户端通讯普通代码

#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <memory.h>
int main(int argc, char* argv[])
{
    if (argc < 3)
    {
        printf("usage: %s ip port\n", argv[0]);
        exit(1);
    }
    /*1.创建socket*/
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        exit(1);
    }
    /*2.调用recvfrom 、sendto等函数和服务器双向通信*/
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr);
    //调用connect并不会像TCP编程中的三次握手,只是在内核在记录服务器端的一些地址信息(包括IP、端口等)
    //这样后面即使不调用sendto指定服务器的地址,而只调用send也可以向服务器发送数据。
    //建议调用connect,这样会保证客户端在接收的时候,只接收到来自指定服务器端的数据,而不会收到其它服务器的数据。
    if (connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
    {
        perror("sendto error");;
        exit(1);
    }
    char buffer[1024] = "hello linux";
    //向服务器发送数据报文
    if (sendto(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
    {
        perror("sendto error");
        exit(1);
    }
    else
    {
        //接收服务器端发送的数据报文
        memset(buffer, 0, sizeof(buffer));
        if (recv(sockfd, buffer, sizeof(buffer), 0) < 0)
        {
            perror("recv error");
            exit(0);
        }
        else
        {
            printf("%s", buffer);
        }
    }
    return 0;
}

5,用于传输结构图数据的UDP代码

(1)用于结构体数据传输的服务器代码

#include  
#include  
#include  
#include  
#include  
#include 
#define MAXLINE 1024 
#define SERV_PORT 8888
struct MSG_PACK
{
    char cmd;
    char status;
    short int len;
};
struct host
{
    char UserName[20];       
    char Host[20];             
    char IP[20];               
    char PassWord [20];       
    char SubNet[512];           
    char Mode;               
    char ConState;          
    char Pin[20];               
    char ConTrol;             
    char RandPassword[10];
};
int main(void) 
{ 
    int sockfd;
    struct sockaddr_in servaddr, cliaddr;
    sockfd = socket(AF_INET, SOCK_DGRAM, 0); /* create a socket */
    /* init servaddr */
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    /* bind address and port to socket */
    if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    {
        perror("bind error");
        exit(1);
    }
    do_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
    close(sockfd);
    return 0;
} 


void do_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) 
{
    int n;
    socklen_t len;
    char mesg[MAXLINE];
    for(;;)
    {
        len = clilen;
        n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);  /* waiting for receive data */
        printf ("n:%d  ,  len=%d/n",n,len);
        struct MSG_PACK pocket;
        memcpy(&pocket,mesg,sizeof(struct MSG_PACK));
        printf("~~~~~~~pocket1~~~~~~~%d/n",pocket.cmd);
        printf("~~~~~~~pocket2~~~~~~~%d/n",pocket.status);
        printf("~~~~~~~pocket3~~~~~~~%d/n",pocket.len);
        struct host sHost2 ;
        memcpy(&sHost2 , mesg + sizeof(struct MSG_PACK) , sizeof(struct host));
        printf("-----sHost1-------%s/n",sHost2.UserName);
        printf("-----sHost2-------%s/n",sHost2.Host);
        printf("-----sHost3-------%s/n",sHost2.IP);
        printf("-----sHost4-------%s/n",sHost2.PassWord);
        printf("-----sHost5-------%s/n",sHost2.SubNet);
        printf("-----sHost6-------%d/n",sHost2.Mode);
        printf("-----sHost7-------%d/n",sHost2.ConState);
        printf("-----sHost8-------%s/n",sHost2.Pin);
        printf("-----sHost9-------%d/n",sHost2.ConTrol);
        printf("-----sHost10-------%s/n",sHost2.RandPassword);
        n = sendto(sockfd, mesg, n, 0, pcliaddr, len);      /* 回发给client */
    }
} 

(2)用于结构体数据传输的客户端代码

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

#define minornode                 0    //从节点向主节点发送连接请求
#define hostnode_return           1    //主节点响应从节点的请求
#define minornode_change          2    //从节点向主节点发送更新请求
#define hostnode_returnchange     3    //主节点响应更新请求

    //包头的定义
    struct MSG_PACK
    {
        char cmd;
        char status;
        short int len;
    };
    


    //定义host
  struct host
  {
          char UserName[20];        
        char Host[20];              
        char IP[20];                
        char PassWord [20];        
        char SubNet[512];            
        char Mode;                
        char ConState;           
        char Pin[20];                
        char ConTrol;              
        char RandPassword[10];
  };

int main()
{
    char sentbuf[1024];
    
    struct host newhost;
    
    memset(&newhost,0,sizeof(struct host));
    
      strcpy(newhost.UserName,"aaaa");
    strcpy(newhost.Host,"www");
    strcpy(newhost.IP,"192.168.8.103");
    strcpy(newhost.PassWord,"1111");
    strcpy(newhost.SubNet,"255.255.255.0");
    newhost.Mode=0;
    newhost.ConState=1;
    strcpy(newhost.Pin,"20");
    newhost.ConTrol=0;
    strcpy(newhost.RandPassword,"122122");
    //printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %s %s %s %s %s %d %d %s %d %s @@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",newhost.UserName,newhost.Host,newhost.IP,newhost.PassWord,newhost.SubNet,newhost.Mode,newhost.ConState,newhost.Pin,newhost.ConTrol,newhost.RandPassword);
    
    struct MSG_PACK newpack;
    newpack.cmd=1;
    newpack.status=1;
    newpack.len=sizeof(newhost);
    //printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %d %d %d @@@@@@@@@@@@@@@@@@@@@@@@@@@ ",newpack.cmd,newpack.status,newpack.len);
    memcpy(sentbuf,&newpack,sizeof(struct MSG_PACK));
    memcpy(sentbuf+sizeof(struct MSG_PACK),&newhost,sizeof(struct host));
    int iLen = sizeof(struct MSG_PACK)+ sizeof(struct host);
    printf("-=-=-=-=-=-=-=-=-=-=-=-=%d  ",iLen);
    int sock; 
    //sendto中使用的对方地址
    struct sockaddr_in servaddr;
    //在recvfrom中使用的对方主机地址
    struct sockaddr_in fromAddr;

  
    unsigned int fromLen;
    char recvBuffer[1024];
    sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_addr.s_addr=inet_addr("192.168.8.200");
    servaddr.sin_port = htons(8000);
    if(sendto(sock,sentbuf,iLen,0,(struct sockaddr*)&servaddr,sizeof(servaddr)) != iLen)
    {
         perror("sendto error"); 
         close(sock);
         exit(1);
    }
    fromLen = sizeof(fromAddr);
    if(recvfrom(sock,recvBuffer,1024,0,(struct sockaddr*)&fromAddr,&fromLen)<0)
    {
         perror("recvfrom error"); 
         close(sock);
         exit(1);
    }
    struct MSG_PACK pocket;
    memcpy(&pocket , recvBuffer , sizeof(struct MSG_PACK));
    
    printf("-----pocket1------->%d ",pocket.cmd);
    printf("-----pocket2------->%d ",pocket.status);
    printf("-----pocket3------->%d ",pocket.len);
    
    struct host sHost2 ;
    memcpy(&sHost2 , recvBuffer + sizeof(struct MSG_PACK) , sizeof(struct host));
    printf("&&&&&&&&&&&&&&&&&&&& -----sHost1------->%s ",sHost2.UserName);
    printf("-----sHost2------->%s ",sHost2.Host);
    printf("-----sHost3------->%s ",sHost2.IP);
    printf("-----sHost4------->%s ",sHost2.PassWord);
    printf("-----sHost5------->%s ",sHost2.SubNet);
    printf("-----sHost6------->%d ",sHost2.Mode);
    printf("-----sHost7------->%d ",sHost2.ConState);
    printf("-----sHost8------->%s ",sHost2.Pin);
    printf("-----sHost9------->%d ",sHost2.ConTrol);
    printf("-----sHost10------->%s &&&&&&&&&&&&&&&&&&&& ",sHost2.RandPassword);
    
    close(sock);
    return 0;
}

​

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒听雪落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值