Running Environment: linux2.6 or above
File Description: tcputil. c --------------- TCP multi-threaded service framework implementation
Tcputil. h --------------- publish function declaration
Instructions for use:
Messages must be sent in a fixed stream boundary (Message Size, message body). The message size is uint32_t type and is in the network byte sequence.
You can directly call start (Listening to IP addresses, listening ports, and custom message processing functions). It mainly provides custom message processing functions. The prototype is:
Int msg_handler (INT socket, void * Buf, uint32_t N), where: socket-socket for receiving messages, Buf-message body memory, and n-message body length.
Key points:
(1) the method for sending and receiving n Bytes is implemented in the readn () and writen () functions;
(2) When passing parameters to the derived thread, pay attention to the synchronization problems caused by concurrency. For details, refer to the parameter passing implementation in the START () function;
(3) Follow "malloc and free must exist in the same function in pairs", but (2) Is there a better solution in violation of this principle?
(4) Adopt the callback function mechanism (similar to the event in C #) to allow the library to use the custom message processing function (this is also to follow the (3) policy );
(5) The TCP stream boundary adopts the (Message Size, message body) method. The message size is a 4-byte unsigned integer.
Problems:
(1) performance problems: at present, the same memory size as the message body is directly allocated to receive the message body;
(2) There is a big message problem. Currently, messages cannot exceed the maximum value of int32_t. for transmission of large data volumes, please implement Custom User message formats in the message body to transmit big data in blocks;
Source 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>#include <sys/types.h>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
Source code: tcputil. c
/************************************************** * * $description: collection of functions * $author: smstong * $date: Tue Apr 16 10:24:22 CST 2013 * * ************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/types.h>/************************************************** * func: receive n bytes from socket except an error * params: fd - socket handle * buf - memory space to write * n - size of buf * return: -1 - error; * >=0 - actually retceived bytes *************************************************/ssize_t recvn(int fd, void* buf, size_t n){char* ptr = (char*)buf; // position pointersize_t left = n;// bytes left to readwhile(left > 0) {size_t nread = read(fd, ptr, left);if(nread<0) {if(errno==EINTR) { // an error occurednread = 0;} else {return -1;}} else if(nread==0) { //normally disconnect, FIN segment receivedbreak;} else {left -= nread;ptr += nread;}}return (n-left);}/******************************************************** * function: write n bytes to socket except error * params: fd - socket hanle * buf - src memory * n - bytes to write * return: -1 - error * >=0 - bytes actually written * ******************************************************/ssize_t writen(int fd, void* buf, size_t n){char* ptr = (char*)buf;size_t left = n;while(left > 0) {size_t nwrite = write(fd, ptr,left); if(nwrite<0) {if(errno==EINTR) {nwrite = 0;} else {return -1;}} else if(nwrite==0) {break;} else {left -= nwrite;ptr += nwrite;}}return (n-left);}static void * thread_f(void *); //thread function typedef int (*message_handler)(int, void *, uint32_t); // callback function called after received one message/************************************************************* * * one thread per connection frameset * * ***********************************************************/// thread function's argsstruct thread_arg {int socket;message_handler msg_handler;};int start(uint32_t listenip, uint16_t listenport, message_handler handler){int listenfd, connfd;struct sockaddr_in servaddr;char buff[4096];int n;if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);exit(0);}memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(listenip);servaddr.sin_port = htons(listenport);if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);return -1;}if( listen(listenfd, 10) == -1){printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);return -1;}printf("======waiting for client's request======\n");while(1){if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){printf("accept socket error: %s(errno: %d)",strerror(errno),errno);continue;}/* create a new thread to handle this connection */pthread_t tid = 0;int rc = 0;struct thread_arg *parg = malloc(sizeof(struct thread_arg));if(NULL==parg) {printf("error malloc: %s\n", strerror(errno));return -1;}parg->socket = connfd;parg->msg_handler = handler;if(0 != (rc=pthread_create(&tid, NULL, thread_f, parg))) {printf("%s: %s\n", __func__, strerror(rc));}printf(" create thread %u to handle connection %d \n", tid, connfd);}close(listenfd);return 0;}/*************************** * fun: receive one message * params: connfd - socket handle * return: 0 - success; * -1 - error * * **************************/static int recv_one_message(int connfd, message_handler post_recv_one){uint32_t msg_len = 0; /* message length *//* recv length */if(4 != recvn(connfd, &msg_len, 4)) { // something wrongreturn -1;}msg_len = ntohl(msg_len);/* recv body */if(msg_len > 0x7FFFFFFF) {printf("message body to large\n");return -1;}char* buf = malloc(msg_len);/* allocate memory for message body*/if(NULL == buf) {printf("%s: malloc failed!\n", __func__);return -1;}if(msg_len != recvn(connfd, buf, msg_len)) {free(buf);return -1;}if(0!=post_recv_one(connfd, buf, msg_len)) { // callbackfree(buf);return -1;}free(buf);return 0;}/* thread to handle a connection */static void * thread_f(void * arg) {printf(" enter thread %u\n", pthread_self());struct thread_arg targ = *((struct thread_arg*)arg); int connfd = targ.socket;message_handler post_recv_one = targ.msg_handler;free(arg);int i = 0;while(1) {if(0 != recv_one_message(connfd, post_recv_one)) {break;}printf("message : %d\n", i++);}close(connfd);printf(" leave thread %u\n", pthread_self());}
Source code: test example server. C. The received message is written to the file data.
#include "tcputil.h"#include <stdio.h>/* callback called after one message received. */int msg_handler(int fd, void* buf, uint32_t n){ char* msg = (char*)buf; FILE* fp = fopen("data", "w"); if(NULL == fp) { printf("%s\n", strerror(errno)); fclose(fp); return -1; } if(n != fwrite(msg, 1, n, fp)) { printf("write error:\n"); fclose(fp); return -1; } fclose(fp); return 0;}int main(int argc, char** argv){ start(0,6666, msg_handler);}
Source code: client program C #
Using system; using system. io; using system. net; using system. net. sockets; namespace consoleapplication1 {class program {static void main (string [] ARGs) {sendtcpmsg (file. readallbytes (@ "F: \ core software backup \ tomatowin2k3. sp2.r2. ISO ");} static void sendtcpmsg (byte [] msgbody) {socket sock = NULL; try {sock = new socket (addressfamily. interNetwork, sockettype. stream, protocoltype. TCP); sock. connect ("172.16.35.135 ", 6666); byte [] msghead = bitconverter. getbytes (IPaddress. hosttonetworkorder (msgbody. length); sock. send (msghead); sock. send (msgbody);} catch (exception ex) {console. write (ex. message);} finally {If (sock! = NULL) sock. Close ();}}}}