socket学习小结

来源:互联网 发布:窗帘软件窗帘梦工场 编辑:程序博客网 时间:2024/05/09 02:28
最近一直都在练习socket编程,发现网上很多帖子给出的例子都比较简单,不知是我自己理解出问题了还是怎么的,在实践中遇到很多问题,现总结一下自己的体会:
1.首先,socket只是提供一个数据交互的通道,socket对于传输的数据是不加辨识,一视同仁的。所以对于数据的解析,需要编程人员自己构建一个简单的协议来解析接收到的数据。
(PS:网上很多帖子都是client向server发送一串字符,然后server打印出这串字符就over了,其实在实际应用中,这种模型太过于简单)
2.socket数据传输的实际过程:
http://blog.csdn.net/shanzhizi/article/details/7659108
这篇帖子可以让读者明白send/recv到底是如何运作的,而且你传输的数据在网络上是怎么传输的。
3.附上自己写的一个实例:
client连续向server发送十次独立的数据(可以看做是十个请求),server每接到一个请求,都需要向client做出答复。
socket.h:定义自己的结构

#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <sys/un.h>#include <sys/select.h>#include <sys/poll.h>#include <string.h>#include <errno.h>#include "list.h"#define UNIX_DOMAIN "/tmp/UNIX.domain" #define CMD_1K 1024typedef int sint32;typedef unsigned int uint32;typedef unsigned char uint8;typedef struct cmd_head{ sint32 len;}cmd_head_t;typedef struct cmd_desc{ cmd_head_t head; uint8 data[0];}cmd_t;typedef struct data_node{ list_t node; cmd_t *cmd;}data_t;cmd_t *cmd_init(sint32 size,sint32 unit);sint32 cmd_set_len(cmd_t *cmd,sint32 len);sint32 my_recv(int socket,cmd_t *cmd);

socket.c:定义一些自己的函数

#include "socket.h"cmd_t *cmd_init(sint32 size,sint32 unit){ return (cmd_t *)calloc(size,unit);}sint32 cmd_set_len(cmd_t *cmd,sint32 len){ if(cmd == NULL) { printf("%s %d err\n",__func__,__LINE__); return -1; } cmd->head.len = len; return 0;}sint32 my_recv(int socket,cmd_t *cmd){ uint8 *buf = NULL; sint32 templen = 0; sint32 temptemplen = 0; sint32 recvlen = 0; sint32 firstrecv = 0; buf = (uint8 *)cmd; do{ templen = 0; if(firstrecv == 0) { do { temptemplen = recv(socket,buf + templen, sizeof(cmd_head_t) - templen,0); if(!(temptemplen > 0)) { return -1; } else if((temptemplen + templen) < sizeof(cmd_head_t)) { templen += temptemplen; continue; } else if((temptemplen + templen) == sizeof(cmd_head_t)) { templen += temptemplen; break; } else { return -1; } }while(1); recvlen = templen; firstrecv++; } if((cmd->head.len + sizeof(cmd_head_t)) == recvlen) { printf("head.len=%d recvlen=%d\n",cmd->head.len,recvlen); break; } if((cmd->head.len + sizeof(cmd_head_t)) < recvlen) { printf("over recv len=%d,recvlen=%d\n",cmd->head.len,recvlen); break; } templen = recv(socket,buf + recvlen, (cmd->head.len + sizeof(cmd_head_t)) - recvlen,0); if(!(templen > 0)) { printf("%d recv err\n",__LINE__); return -1; } recvlen += templen; if (recvlen > (cmd->head.len + sizeof(cmd_head_t))){ printf("over recv, recvlen:%d, scmdlen:%d !\n", recvlen, (cmd->head.len + sizeof(cmd_head_t))); break; } }while(recvlen != (cmd->head.len + sizeof(cmd_head_t))); return recvlen;}

list.h:关于链表的一些操作函数

#ifndef _LIST_H#define _LIST_H1#undef NULL#if defined(__cplusplus)#define NULL 0#else#define NULL ((void *)0)#endif/* The definitions of this file are adopted from those which can be found in the Linux kernel headers to enable people familiar with the latter find their way in these sources as well. *//* Basic type for the double-link list. */typedef struct list_head{ struct list_head *next; struct list_head *prev;} list_t;#ifdef _LIST_H//# include <atomic.h>/* Define a variable with the head and tail of the list. */# define LIST_HEAD(name) \ list_t name = { &(name), &(name) }/* Initialize a new list head. */# define INIT_LIST_HEAD(ptr) \ (ptr)->next = (ptr)->prev = (ptr)static inline int list_empty(list_t *head){return (head->next== head) ;}/* Add new element at the head of the list. */static inline voidlist_add (list_t *newp, list_t *head){newp->next = head->next;newp->prev = head;head->next->prev = newp;head->next = newp;}static inline voidlist_add_tail(list_t *newp, list_t *head){newp->next = head;newp->prev = head->prev;head->prev->next= newp;head->prev = newp;}/*get the first element next to head*/static inline list_t *list_get_first(list_t *head){if(list_empty(head))return NULL;return head->next;}/* Remove element from list. */static inline voidlist_del (list_t *elem){elem->next->prev = elem->prev;elem->prev->next = elem->next;}/* Join two lists. */static inline voidlist_splice (list_t *add, list_t *head){ /* Do nothing if the list which gets added is empty. */ if (add != add->next) { add->next->prev = head; add->prev->next = head->next; head->next->prev = add->prev; head->next = add->next; }}/* Get typed element from list at a given position. */# define list_entry(ptr, type, member) \ ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))/* Iterate forward over the elements of the list. */# define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next)/* Iterate forward over the elements of the list. */# define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); pos = pos->prev)/* Iterate backwards over the elements list. The list elements can be removed from the list while doing this. */# define list_for_each_prev_safe(pos, p, head) \ for (pos = (head)->prev, p = pos->prev; \ pos != (head); \ pos = p, p = pos->prev)#endif /* _LIST_H */#endif/* list.h */

client.c:客户端,即请求发起者

#include "socket.h"int main(){ sint32 sock; sint32 ret; sint32 num; uint8 buf2[10]; fd_set fdset; struct sockaddr_un send_addr; cmd_t *cmd = NULL; uint8 buf[] = "U can u up,No can no bb"; sock = socket(PF_UNIX,SOCK_STREAM,0); if(sock < 0) { printf("socket err\n"); return -1; } send_addr.sun_family = AF_UNIX; strcpy(send_addr.sun_path,UNIX_DOMAIN); ret = connect(sock,(struct sockaddr *)&send_addr, sizeof(struct sockaddr_un)); if(ret == -1) { perror("connect err\n"); return -1; } FD_ZERO(&fdset); FD_SET(sock,&fdset); cmd = cmd_init(CMD_1K,sizeof(uint8)); if(cmd == NULL) { printf("cmd_init err\n"); return -1; } for(ret = 0;ret < 10;ret++) { memset(buf2,0,10); memset(cmd,0,sizeof(cmd_t)); memcpy(cmd->data,buf,strlen(buf) + 1); sprintf(buf2,"%d",ret); strcat(cmd->data,buf2); cmd_set_len(cmd,strlen(buf) + 1 + 1); num = send(sock,cmd,cmd->head.len + sizeof(cmd_head_t),0); if(ret < 0) { perror("send err"); break; } printf("The cmd(%d) %s has been send len %d\n",ret,cmd->data,num); } if(select(sock + 1,&fdset,NULL,NULL,NULL) < 0) { perror("select err"); return -1; } if(FD_ISSET(sock,&fdset)) { ret = 0; do{ if(ret == 10) { break; } memset(cmd->data,0,CMD_1K - sizeof(cmd_head_t)); num = my_recv(sock,cmd); ret ++; printf("I recv cmd(%d:%d) %s\n",ret,num,cmd->data); }while(num > 0); } close(sock);}

server.c:服务器段,即命令处理者

#include "socket.h"list_t data_list;int fd;void *data_proc(void *prg){ list_t *p = NULL; data_t *node = NULL; for(;;) { while((p = list_get_first(&data_list)) != NULL) { node = list_entry(p,data_t,node); printf("send(%s):%d \n",node->cmd->data,node->cmd->head.len + sizeof(cmd_head_t)); send(fd,node->cmd,node->cmd->head.len + sizeof(cmd_head_t),0); list_del(&node->node); free(node); } }}int main(){ sint32 sock; sint32 recv; sint32 num; sint32 ret; sint32 len; sint32 on=1; pthread_t pid = 0; data_t *data = NULL; cmd_t *recv_cmd = NULL; struct sockaddr_un clt_addr; struct sockaddr_un srv_addr; struct pollfd pfd; INIT_LIST_HEAD(&data_list); if(pthread_create(&pid,NULL,data_proc,NULL) < 0) { perror("thread create err"); return -1; } sock = socket(PF_UNIX,SOCK_STREAM,0); if(sock<0) { perror("cannot create communication socket"); return 1; } if((setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0) { perror("setsockopt failed"); return -1; } recv_cmd = cmd_init(CMD_1K,sizeof(uint8)); if(recv_cmd == NULL) { printf("cmd init err\n"); close(sock); return -1; } srv_addr.sun_family=AF_UNIX; strcpy(srv_addr.sun_path,UNIX_DOMAIN); unlink(UNIX_DOMAIN); ret=bind(sock,(struct sockaddr*)&srv_addr,sizeof(struct sockaddr_un)); if(ret==-1) { perror("cannot bind server socket"); close(sock); unlink(UNIX_DOMAIN); return -1; } ret=listen(sock,1); if(ret==-1) { perror("cannot listen the client connect request"); close(sock); unlink(UNIX_DOMAIN); return -1; } pfd.fd = sock; pfd.events = POLLIN; len=sizeof(struct sockaddr_un); for(;;) { poll(&pfd,1,-1); recv = accept(sock,(struct sockaddr*)&clt_addr,&len); if(sock<0) { perror("cannot accept client connect request"); close(sock); unlink(UNIX_DOMAIN); return -1; } fd = recv; ret = 0; do{ memset(recv_cmd->data,0,CMD_1K - sizeof(cmd_head_t)); printf("before recv\n"); num=my_recv(recv,recv_cmd); ret++; printf("Message from client (%d:%d)) :%s\n",ret,num,recv_cmd->data); if(num > 0) { data = (data_t *)calloc(sizeof(data_t),sizeof(char)); if(data == NULL) { printf("calloc err\n"); continue; } data->cmd = cmd_init(CMD_1K,sizeof(uint8)); memcpy(data->cmd->data,recv_cmd->data,num - sizeof(cmd_head_t)); data->cmd->head.len = num - sizeof(cmd_head_t); list_add_tail(&data->node,&data_list); } }while(num > 0); } printf("Game voer\n"); close(sock); unlink(UNIX_DOMAIN); return 0;}

代码写得不是很规范,望各位多多指正。但是代码功能是可以的

0 0
原创粉丝点击