首页 > 代码库 > linux网络编程笔记——TCP

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)\n",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)\n",strerror(errno),errno);
110         return -1;
111     }
112 
113     if( listen(listenfd, 10) == -1){
114         printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
115         return -1;
116     }
117 
118     printf("======waiting for client‘s request======\n");
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\n", 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\n", __func__, strerror(rc));
136         }
137         printf(" create thread %u to handle connection %d \n", 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\n",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!\n", __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\n", 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\n",connfd,i++);
201     }
202     close(connfd);
203     printf(" leave thread %u\n", 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,"\nrover\n",strlen("\nrover\n")))
    {
        writen(fd, (char *)diff, sizeof(diff_t));
        printf("\t\tsend\n\n"); 
    }
    if (!strncmp(buf,"\nstation\n",strlen("\nstation\n")))
    {
        memcpy((char *)diff, buf+strlen("\nstation\n"), sizeof(diff_t));
        printf("\t\tupdate\n\n"); 
    }

    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\n");
        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!\n");
    printf("I am rover!\n");
    printf("Connected to %s:%d\n", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));

    char tag[]="\nrover\n";

    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\n");
        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!\n");
    printf("I am station!\n");
    printf("Connected to %s:%d\n", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));

    char tag[]="\nstation\n";

    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\n", msg_len);
        if(write(sock,msg,msg_len) != msg_len)
        {
            perror("write");
        }
        sleep(1);
    }
    free(msg);
    close(sock);
    return 0;
}
View Code

 

附上makefile一枚

+ View Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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