• linux网络编程笔记——TCP


    1、TCP和UDP

    TCP是长连接像持续的打电话,UDP是短消息更像是发短信。TCP需要消耗相对较多的资源,但是传输质量有保障,UDP本身是不会考虑传输质量的问题。

    2、网络传输内容

    我习惯的做法是直接通过TCP传送结构体,当然前提是收发两端都在程序里对目标结构体有充分的定义。特别说明的一点是,要小心收发两端处理器的大小端问题!而且传输信息头里必须包含长度信息,而且通用的是大端。但是,这里的长度和结构体,我选择用小端进行传输。

    3、TCPserver实现

    参考了别人多线程的回调写法,看起来不错。

    tcputil.c(照搬别人的,文件内有作者信息)

      1 /**************************************************
      2  *
      3  * $description: collection of functions 
      4  * $author: smstong
      5  * $date: Tue Apr 16 10:24:22 CST 2013
      6  *
      7  * ************************************************/
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <errno.h>
     12 #include <sys/types.h>
     13 #include <sys/socket.h>
     14 #include <netinet/in.h>
     15 #include <pthread.h>
     16 /**************************************************
     17  * func: receive n bytes from socket except an error
     18  * params: fd - socket handle
     19  *            buf - memory space to write
     20  *            n - size of buf 
     21  * return: -1 - error;
     22  *            >=0 - actually retceived bytes
     23  *************************************************/
     24 ssize_t recvn(int fd, void* buf, size_t n)
     25 {
     26     char* ptr = (char*)buf; // position pointer
     27     size_t left = n;        // bytes left to read
     28     while(left > 0) {
     29         size_t nread = read(fd, ptr, left);
     30         if(nread<0)  {
     31             if(errno==EINTR) { // an error occured
     32                 nread = 0;
     33             } else {
     34                 return -1;
     35             }
     36         } else if(nread==0) { //normally disconnect, FIN segment received
     37             break;
     38         } else {
     39             left -= nread;
     40             ptr += nread;
     41         }
     42     }
     43     return (n-left);
     44 }
     45 
     46 /********************************************************
     47  * function: write n bytes to socket except error
     48  * params: fd - socket hanle 
     49  *            buf - src memory 
     50  *            n - bytes to write 
     51  * return: -1 - error
     52  *            >=0 - bytes actually written
     53  * ******************************************************/
     54 ssize_t writen(int fd, void* buf, size_t n)
     55 {
     56     char* ptr = (char*)buf;
     57     size_t left = n;
     58     while(left > 0) {
     59         size_t nwrite = write(fd, ptr,left);
     60         if(nwrite<0) {
     61             if(errno==EINTR) {
     62                 nwrite = 0;
     63             } else {
     64                 return -1;
     65             }
     66         } else if(nwrite==0) {
     67             break;
     68         } else {
     69             left -= nwrite;
     70             ptr += nwrite;
     71         }    
     72     }
     73     return (n-left);
     74 }
     75 
     76 static void * thread_f(void *); //thread function 
     77 typedef int (*message_handler)(int, void *, uint32_t); // callback function called after received one message
     78 
     79 /*************************************************************
     80  *
     81  * one thread per connection frameset
     82  *
     83  * ***********************************************************/
     84 
     85 // thread function's args
     86 struct thread_arg {
     87     int socket;
     88     message_handler msg_handler;
     89 };
     90 
     91 int start(uint32_t listenip, uint16_t listenport, message_handler handler)
     92 {    
     93     int    listenfd, connfd;
     94     struct sockaddr_in     servaddr;
     95     char    buff[4096];
     96     int     n;
     97 
     98     if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
     99         printf("create socket error: %s(errno: %d)
    ",strerror(errno),errno);
    100         exit(0);
    101     }
    102 
    103     memset(&servaddr, 0, sizeof(servaddr));
    104     servaddr.sin_family = AF_INET;
    105     servaddr.sin_addr.s_addr = htonl(listenip);
    106     servaddr.sin_port = htons(listenport);
    107 
    108     if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
    109         printf("bind socket error: %s(errno: %d)
    ",strerror(errno),errno);
    110         return -1;
    111     }
    112 
    113     if( listen(listenfd, 10) == -1){
    114         printf("listen socket error: %s(errno: %d)
    ",strerror(errno),errno);
    115         return -1;
    116     }
    117 
    118     printf("======waiting for client's request======
    ");
    119     while(1){
    120         if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){
    121             printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
    122             continue;
    123         }
    124         /* create a new thread to handle this connection */
    125         pthread_t tid = 0;
    126         int rc = 0;
    127         struct thread_arg *parg = malloc(sizeof(struct thread_arg));
    128         if(NULL==parg) {
    129             printf("error malloc: %s
    ", strerror(errno));
    130             return -1;
    131         }
    132         parg->socket = connfd;
    133         parg->msg_handler = handler;
    134         if(0 != (rc=pthread_create(&tid, NULL, thread_f, parg))) {
    135             printf("%s: %s
    ", __func__, strerror(rc));
    136         }
    137         printf(" create thread %u to handle connection %d 
    ", tid, connfd);    
    138     }
    139     close(listenfd);
    140     return 0;
    141 }
    142 /***************************
    143  * fun: receive one message
    144  * params: connfd - socket handle
    145  * return: 0 - success;
    146  *            -1 - error
    147  *
    148  * **************************/
    149 static int recv_one_message(int connfd, message_handler post_recv_one)
    150 {
    151     uint32_t msg_len = 0;         /* message length */
    152     
    153     /* recv length */
    154     if(4 != recvn(connfd, &msg_len, 4)) { // something wrong
    155         return -1;
    156     }
    157 
    158                 /*很重要的函数,内存*/
    159     //msg_len = ntohl(msg_len);
    160 
    161     /* recv body */
    162     if(msg_len > 0x7FFFFFFF) {
    163         printf("message body to large%d
    ",msg_len);
    164         return -1;
    165     }
    166 
    167     char* buf = malloc(msg_len);/* allocate memory for message body*/
    168     if(NULL == buf) {
    169         printf("%s: malloc failed!
    ", __func__);
    170         return -1;
    171     }
    172 
    173     if(msg_len != recvn(connfd, buf, msg_len)) {
    174         free(buf);
    175         return -1;
    176     }
    177 
    178     if(0!=post_recv_one(connfd, buf, msg_len)) { // callback
    179         free(buf);
    180         return -1;
    181     }
    182 
    183     free(buf);
    184     return 0;
    185 }
    186 /* thread to handle a connection */
    187 static void * thread_f(void * arg) 
    188 {
    189     printf(" enter thread %u
    ", pthread_self());
    190     struct thread_arg targ = *((struct thread_arg*)arg); 
    191     int connfd = targ.socket;
    192     message_handler post_recv_one = targ.msg_handler;
    193     free(arg);
    194 
    195     int i = 0;
    196     while(1) {
    197         if(0 != recv_one_message(connfd, post_recv_one)) {
    198             break;
    199         }
    200         printf("%d message : %d
    ",connfd,i++);
    201     }
    202     close(connfd);
    203     printf(" leave thread %u
    ", pthread_self());
    204 }
    View Code

    tcputil.h

    #ifndef TCPUTIL_H
    #define TCPUTIL_H
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    //结构体在内存里紧凑排列
    #pragma pack(1)
    typedef struct {        /* raw data */
        double tow;    // GPS time of the week in second
        unsigned char numGps;
        unsigned char numBds;
        unsigned char numGln;
        unsigned char system[MAXSAT];    // system, 0, 1, 2 GPS, BDS & GLN
        unsigned char PRN[MAXSAT];    // PRN number
        double dDO[MAXSAT];    // Doppler in Hz
        double dPR[MAXSAT];    // pseudorange in meter
    } diff_t;
    #pragma pack()
    
    ssize_t writen(int fd, void* buf, size_t n); 
    ssize_t recvn(int fd, void* buf, size_t n); 
    
    /*callback function called after received one message, 0-success, -1-error*/
    typedef int (*message_handler)(int socket, void * buf, uint32_t size);
    
    int start(uint32_t listenip, uint16_t listenport, message_handler handler);
    
    #endif
    View Code

    server.c

    #include "tcputil.h"
    
    diff_t *diff;
    
    /* callback called after one message received. */
    int msg_handler(int fd, void* buf, uint32_t n)
    {
        if (!strncmp(buf,"
    rover
    ",strlen("
    rover
    ")))
        {
            writen(fd, (char *)diff, sizeof(diff_t));
            printf("		send
    
    "); 
        }
        if (!strncmp(buf,"
    station
    ",strlen("
    station
    ")))
        {
            memcpy((char *)diff, buf+strlen("
    station
    "), sizeof(diff_t));
            printf("		update
    
    "); 
        }
    
        return 0;
    }
    
    int main(int argc, char** argv)
    {   
        diff=malloc(sizeof(diff_t));
        bzero(diff,sizeof(diff_t));
        start(0,PORT, msg_handler);
        free(diff);
    }
    View Code

    4、TCPclient实现

    略粗糙,将就着看吧

    rover.c

    #include "tcputil.h"
    
    int main(int argc, const char *argv[])
    {
        diff_t *diff=malloc(sizeof(diff_t));
        bzero(diff,sizeof(diff_t));
    
        struct sockaddr_in addr;
        int sock;
    
        if(argc != 2)
        {
            fprintf(stderr,"need an IP address
    ");
            return 1; 
        }
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        inet_aton(argv[1],&addr.sin_addr);
        addr.sin_port = htons(PORT);
        if(       (sock = socket(PF_INET, SOCK_STREAM,0))     <  0        )
        {
            perror("socket");
        } 
        if(      connect(sock, (struct sockaddr *)&addr, sizeof(addr))    )
        {
            perror("connect");
        }
        printf("Connected!
    ");
        printf("I am rover!
    ");
        printf("Connected to %s:%d
    ", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
    
        char tag[]="
    rover
    ";
    
        uint32_t len = strlen(tag), msg_len=4+strlen(tag);
    
        char *msg=malloc(msg_len);
        bzero(msg,msg_len);
    
        memcpy(msg,&len,4);
        memcpy(msg+4,tag,len);
    
        while(1){
            sleep(1);
            if(write(sock,msg,msg_len) != msg_len)
            {
                perror("write");
            }
            read(sock,(char *)diff,sizeof(diff_t));
        }
    
        free(msg);
        close(sock);
        return 0;
    }
    View Code

    station.c

    #include "tcputil.h"
    
    int main(int argc, const char *argv[])
    {
        struct sockaddr_in addr;
        int sock;
    
        diff_t *diff=malloc(sizeof(diff_t));
        bzero(diff,sizeof(diff_t));
    
        if(argc != 2)
        {
            fprintf(stderr,"need an IP address
    ");
            return 1; 
        }
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        inet_aton(argv[1],&addr.sin_addr);
        addr.sin_port = htons(PORT);
        if(       (sock = socket(PF_INET, SOCK_STREAM,0))     <  0        )
        {
            perror("socket");
        } 
        if(      connect(sock, (struct sockaddr *)&addr, sizeof(addr))    )
        {
            perror("connect");
        }
        printf("Connected!
    ");
        printf("I am station!
    ");
        printf("Connected to %s:%d
    ", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
    
        char tag[]="
    station
    ";
    
        uint32_t len =   strlen(tag)+sizeof(diff_t);
        int  msg_len = 4+strlen(tag)+sizeof(diff_t);
        char *msg=malloc(msg_len);
        bzero(msg,msg_len);
    
        memcpy(msg,&len,4);
        memcpy(msg+4,tag,strlen(tag));
    
        while(1){
            memcpy(msg+4+strlen(tag),diff,sizeof(diff_t));
                printf("!!!!!!!!!!!!%d
    ", msg_len);
            if(write(sock,msg,msg_len) != msg_len)
            {
                perror("write");
            }
            sleep(1);
        }
        free(msg);
        close(sock);
        return 0;
    }
    View Code

    附上makefile一枚

    all:    rover server station
    
    rover:  rover.c tcputil.o
    	gcc rover.c tcputil.o -o rover -lpthread
    
    server: server.c tcputil.o
    	gcc server.c tcputil.o -o server -lpthread
    
    station:station.c tcputil.o
    	gcc station.c tcputil.o -o station -lpthread
    
    tcputil:tcputil.c 
    	gcc tcputil.c -c -lpthread
    
    .PHONY: clean
    
    clean:
    	rm -f *.o rover server station
    

      

  • 相关阅读:
    VS2013安装与部署工具中添加 vcredist_x64.exe
    ZeroMQ高水位标记(high-water mark,HWM)
    Ubuntu16.04 动态链接库(.so)查询路径设置
    ubuntu16.04开机启动字符界面
    python 全局搜索路径
    learning to rank
    数据集
    hadoop streaming 文档
    机器学习:一些感想
    矩阵分解 推荐
  • 原文地址:https://www.cnblogs.com/catmelo/p/3736410.html
Copyright © 2020-2023  润新知