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 }
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
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); }
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; }
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; }
附上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
作者:catmelo
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。