socket编写简单回显server
socket在公司代码中应用比较广,比如接口调用的IPCRPC机制,经常看到这样的代码,但是一直也没有动手写过。
在某个比较大的进程中创建一个子进程,由于父子进程复制会浪费内存,可以将创建进程的命令通过socket发送到另一个轻量级的进程来创建。
在lighttpd和airplay的源码中,socket的框架是类似的。
下面参照lighttpd和airplay写个简单的回显server,以后有空再完善。
server.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
//#define USE_UNIX_SOCKET
#define USE_IPV4_SOCKET
#ifdef USE_UNIX_SOCKET
#include <sys/un.h>
const char * host = "/tmp/fellow.srv.un.addr";
#endif
#ifdef USE_IPV4_SOCKET
const char *host = "127.0.0.1";
const int port = 9090;
#endif
#define FDEVENT_IN (1<<0)
#define FDEVENT_OUT (1<<1)
#define FDEVENT_ERR (1<<2)
typedef struct _FdEvent{
int maxFd;
fd_set select_listen_read_fd;//监听fd
fd_set select_listen_write_fd;
fd_set select_listen_err_fd;
fd_set select_set_read_fd;//每次加入fd到select_set_*_fd,在select前将值赋给监听fd,可以不必每次遍历来初始化监听fd
fd_set select_set_write_fd;
fd_set select_set_err_fd;
}FdEvent;
typedef void (*Handle)(void *context);
typedef struct _SockSource{//每一个监听到的socket对应一个SockSource
int sock;
int sockType;
Handle handle;//当sock有时间发生时,调用handle处理
struct _SockSource *next;
}SockSource;
SockSource *gSockSourceList = NULL;
FdEvent gFdEvent;
SockSource *createSockSource(int sock, int sockType, Handle handle)
{
SockSource *sockSource = (SockSource *)malloc(sizeof(SockSource));
sockSource->sock = sock;
sockSource->sockType = sockType;
sockSource->handle = handle;
sockSource->next = NULL;
return sockSource;
}
void addToSockSourceList(SockSource *sockSource)
{
if (gSockSourceList == NULL)
{
gSockSourceList = sockSource;
}
else
{
sockSource->next = gSockSourceList;
gSockSourceList = sockSource;
}
}
void removeFromSockSourceList(SockSource *sockSource)
{
if (NULL == gSockSourceList) return;
if (gSockSourceList == sockSource)
{
gSockSourceList = sockSource;
if (sockSource) free(sockSource);
}
else
{
SockSource *curSockSource = gSockSourceList;
SockSource *nextSockSource = gSockSourceList->next;
for (; nextSockSource != NULL; nextSockSource = nextSockSource->next)
{
if (nextSockSource == sockSource)
{
curSockSource->next = nextSockSource->next;
if(sockSource) free(sockSource);
break;
}
curSockSource = nextSockSource;
}
}
}
void fdevent_select_reset(FdEvent *ev)
{
FD_ZERO(&(ev->select_set_read_fd));
FD_ZERO(&(ev->select_set_write_fd));
FD_ZERO(&(ev->select_set_err_fd));
ev->maxFd = -1;
}
void fdevent_select_set(FdEvent *ev, int fd, int event)
{
if (fd > (int)FD_SETSIZE) return;
if (event & FDEVENT_IN)
{
FD_SET(fd, &(ev->select_set_read_fd));
}
else
{
FD_CLR(fd, &(ev->select_set_read_fd));
}
if (event & FDEVENT_OUT)
{
FD_SET(fd, &(ev->select_set_write_fd));
}
else
{
FD_CLR(fd, &(ev->select_set_write_fd));
}
if (event & FDEVENT_ERR)
{
FD_SET(fd, &(ev->select_set_err_fd));
}
else
{
FD_CLR(fd, &(ev->select_set_err_fd));
}
if (fd > ev->maxFd) ev->maxFd = fd;
}
int fdevent_select_poll(FdEvent *ev, int time_ms)
{
struct timeval tv;
tv.tv_sec = time_ms /1000;
tv.tv_usec = (time_ms % 1000) * 1000;
ev->select_listen_read_fd = ev->select_set_read_fd;
ev->select_listen_write_fd = ev->select_set_write_fd;
ev->select_listen_err_fd = ev->select_set_err_fd;
return select(ev->maxFd + 1, &(ev->select_listen_read_fd),&(ev->select_listen_write_fd),&(ev->select_listen_err_fd), &tv);
}
void accept_handle(void *context)
{
SockSource *clientSource = (SockSource *)context;
char rcvBuf[1024];
char sndBuf[1024];
memset(&rcvBuf, 0, sizeof(rcvBuf));
memset(&sndBuf, 0, sizeof(sndBuf));
int byteRcv = recv(clientSource->sock, rcvBuf, sizeof(rcvBuf), 0);
if (byteRcv > 0)
{
printf("rcv data: %s, len: %d\n", rcvBuf, byteRcv);
snprintf(sndBuf, sizeof(sndBuf), "server rcv %s\n", rcvBuf);
send(clientSource->sock, sndBuf, strlen(sndBuf)+1, 0);
}
else
{
printf("rcv fail, errno:%d\n", errno);
fdevent_select_set(&gFdEvent, clientSource->sock, 0);
removeFromSockSourceList(clientSource);
}
}
void listen_handle(void *context)
{
SockSource *listenSource = (SockSource *)context;
int client_sock = -1;
size_t addr_len = 0;
#ifdef USE_UNIX_SOCKET
struct sockaddr_un client_addr;
addr_len = strlen(host) + sizeof(client_addr.sun_family);
#endif
#ifdef USE_IPV4_SOCKET
struct sockaddr_in client_addr;
addr_len = sizeof(struct sockaddr_in);
#endif
if (-1 == (client_sock = accept(listenSource->sock, (struct sockaddr*)&client_addr, &addr_len)))
{
switch(errno)
{
case EAGAIN:
#if EAGAIN != EWOULDBLOCK
case EWOULDBLOCK;
#endif
break;
default:
printf("accept fail, errno:%d", errno);
break;
}
}
else
{
fdevent_select_set(&gFdEvent, client_sock, FDEVENT_IN);
SockSource *clientSource = createSockSource(client_sock, (int)FDEVENT_IN, accept_handle);
addToSockSourceList(clientSource);
}
}
int setup_listen_socket()
{
int sock = -1;
socklen_t addr_len;
#ifdef USE_UNIX_SOCKET
struct sockaddr_un srv_addr;
srv_addr.sun_family = AF_UNIX;
if (-1 == (sock = socket(AF_UNIX, SOCK_STREAM, 0)))
{
printf("un socket fail, errno:%d\n", errno);
goto err;
}
size_t hostLen = strlen(host) + 1;
memcpy(srv_addr.sun_path, host, hostLen);
addr_len = hostLen + sizeof(srv_addr.sun_family);
#endif
#ifdef USE_IPV4_SOCKET
struct sockaddr_in srv_addr;
memset(&srv_addr, 0, sizeof(struct sockaddr_in));
srv_addr.sin_family = AF_INET;
if (-1== (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
{
printf("in socket fail, errno:%d\n", errno);
goto err;
}
int val = 1;
if (-1== setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)))
{
printf("setsockopt fail, errno:%d\n", errno);
goto err;
}
if (0 == inet_aton(host, &(srv_addr.sin_addr)))
{
printf("inet_aton fail, errno:%d\n", errno);
goto err;
}
srv_addr.sin_port = htons(port);
addr_len = sizeof(struct sockaddr_in);
#endif
if (0 != bind(sock, (struct sockaddr*)&srv_addr, addr_len))
{
printf("bind fail, errno:%d\n", errno);
goto err;
}
if (0 != listen(sock, 10))
{
printf("inet_aton fail, errno:%d\n", errno);
goto err;
}
fdevent_select_set(&gFdEvent, sock, FDEVENT_IN);
SockSource *listenSource = createSockSource(sock, (int)FDEVENT_IN, listen_handle);
addToSockSourceList(listenSource);
return sock;
err:
if (-1 != sock)
{
close(sock);
}
return -1;
}
void main(void)
{
int sock = -1;
int numOfEvent = 0;
fdevent_select_reset(&gFdEvent);
if(-1 == (sock = setup_listen_socket()))
{
return;
}
printf("listenning sock:%d\n", sock);
while (1)
{
int timeout_ms = 1000;
numOfEvent = fdevent_select_poll(&gFdEvent, timeout_ms);
if (numOfEvent > 0)
{
SockSource *source = NULL;
for (source = gSockSourceList; source != NULL; source = source->next)
{
switch(source->sockType)
{
case FDEVENT_IN:
if (FD_ISSET(source->sock, &(gFdEvent.select_listen_read_fd)))
{
source->handle(source);
numOfEvent--;
}
break;
case FDEVENT_OUT:
if (FD_ISSET(source->sock, &(gFdEvent.select_listen_write_fd)))
{
source->handle(source);
numOfEvent--;
}
break;
case FDEVENT_ERR:
if (FD_ISSET(source->sock, &(gFdEvent.select_listen_err_fd)))
{
source->handle(source);
numOfEvent--;
}
break;
}
}
}
}
}
client端测试代码:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define USE_IPV4_SOCKET
//#define USE_UNIX_SOCKET
#ifdef USE_UNIX_SOCKET
#include <sys/un.h>
const char * host = "/tmp/fellow.srv.un.addr";
#endif
#ifdef USE_IPV4_SOCKET
const char *host = "127.0.0.1";
const int port = 9090;
#endif
void main(void)
{
int sock = -1;
char sndBuf[1024];
char rcvBuf[1024];
socklen_t addr_len;
#ifdef USE_UNIX_SOCKET
struct sockaddr_un srv_addr;
srv_addr.sun_family = AF_UNIX;
if (-1 == (sock = socket(AF_UNIX, SOCK_STREAM, 0)))
{
printf("un socket fail, errno:%d\n", errno);
goto err;
}
size_t hostLen = strlen(host) + 1;
memcpy(srv_addr.sun_path, host, hostLen);
addr_len = hostLen + sizeof(srv_addr.sun_family);
#endif
#ifdef USE_IPV4_SOCKET
struct sockaddr_in srv_addr;
memset(&srv_addr, 0, sizeof(struct sockaddr_in));
srv_addr.sin_family = AF_INET;
if (-1== (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
{
printf("in socket fail, errno:%d\n", errno);
goto err;
}
if (0 == inet_aton(host, &(srv_addr.sin_addr)))
{
printf("inet_aton fail, errno:%d\n", errno);
goto err;
}
srv_addr.sin_port = htons(port);
addr_len = sizeof(struct sockaddr_in);
#endif
if (-1 == connect(sock, (struct sockaddr*)&srv_addr, addr_len))
{
printf("connect fail, errno:%d\n", errno);
goto err;
}
int running = 1;
int count = 0;
while (running)
{
printf("Send your msg to server, finish with end!\n");
fgets(sndBuf, sizeof(sndBuf), stdin);
int dataLen = strlen(sndBuf) + 1;
if (-1 == send(sock, (void*)&sndBuf, dataLen, 0))
{
printf("send fail, errno:%d\n", errno);
goto err;
}
if(!strncmp(sndBuf, "end", strlen("end")))
{
running = 0;
}
if (-1 == recv(sock, (void*)&rcvBuf, sizeof(rcvBuf), 0))
{
printf("recv fail, errno:%d\n", errno);
goto err;
}
printf("data from server: %s\n", rcvBuf);
count++;
}
err:
if(-1 != sock) close(sock);
}
client端测试结果:

server端log

socket编写简单回显server的更多相关文章
- 二、socket编写简单BIO的HTTP服务器
一.目标 诸如tomcat等web服务器中间件简化了我们web的开发成本,但有时候我们或许并不需要这么一个完备的服务器,只是希望做一个简单地处理或者做特殊用途的服务器. 本文将提供一个HTTP的服务器 ...
- 关于Socket编写简单聊天工具的总结(原创)
这段时间再看socket编程,虽然现在是刚刚接触,但是还是忍不住想写一篇总结,来激励自己努力学习,写的不好的地方,还请大家指教啊! 下面针对一个简单的发送消息和文件的程序说说吧. 首先是服务器需要 ...
- Python网络编程——编写一个简单的回显客户端/服务器应用
今天将python中socket模块的基本API学习完后,照着书上的实例编写一个套接字服务器和客户端.采用python3.5版本,在注释中会标明python2和python3的不同之处. 1.代码 ( ...
- libevent的使用方法--回显服务器的简单实例
#include <event.h> #include <sys/types.h> #include <sys/socket.h> #include <net ...
- 用Python编写一个简单的Http Server
用Python编写一个简单的Http Server Python内置了支持HTTP协议的模块,我们可以用来开发单机版功能较少的Web服务器.Python支持该功能的实现模块是BaseFTTPServe ...
- NodeJS+Express+MongoDB 简单实现数据录入及回显展示【适合新人刚接触学习】
近期在看NodeJS相关 不得不说NodeJS+Express 进行网站开发是很不错,对于喜欢玩JS的来说真是很好的一种Web开发组合 在接触NodeJS时受平时Java或者C#中API接口等开发的思 ...
- 编写一个简单的Web Server
编写一个简单的Web Server其实是轻而易举的.如果我们只是想托管一些HTML页面,我们可以这么实现: 在VS2013中创建一个C# 控制台程序 编写一个字符串扩展方法类,主要用于在URL中截取文 ...
- Struts2第十一篇【简单UI标签、数据回显】
Struts2UI标签 Sturts2为了简化我们的开发,也为我们提供了UI标签-也就是显示页面的标签-.. 但是呢,Struts2是服务端的框架,因此使用页面的标签是需要在服务器端解析然后再被浏览器 ...
- Linux终端下简单的登录程序 密码不回显
在Linux进行登录是输入密码不会被回显,所以我也写了个简单的登入程序,使得在输入密码时不再进行回显. #include <stdio.h> #include <stdlib.h&g ...
随机推荐
- IOS中bounds和frame
* 用bounds和frame来修改尺寸是有一些小区别的 三.isEqual:方法 1> 系统会根据对象isEqual方法的返回值来决定两个对象是否相同 * 比如判断对象a和b是否相同,就会查看 ...
- Jave 鼠标点击画太极 PaintTaiji (整理)
package demo; /** * Jave 鼠标点击画太极 PaintTaiji (整理) * 声明: * 又是一份没有注释的代码,而且时间已经久远了,不过代码很短,解读起来应该 * 不会很麻烦 ...
- LSTM网络(Long Short-Term Memory )
本文基于前两篇 1. 多层感知机及其BP算法(Multi-Layer Perceptron) 与 2. 递归神经网络(Recurrent Neural Networks,RNN) RNN 有一个致命的 ...
- 【自动化测试】Selenium excel操作
http://www.cnblogs.com/lhj588/archive/2012/01/06/2314181.html http://blog.csdn.net/five3/article/det ...
- poj 1986 Distance Queries
好像是模板题 当作练习题 不错: 要求任意两点之间的距离.可以假设一个根节点,然后所有点到根节点的距离,然后求出任意两点多公共祖先: 距离就变成了 dis[u]+dis[v] - 2*dis[ ...
- tcp的精髓:滑动窗口
TCP协议作为一个可靠的面向流的传输协议,其可靠性和流量控制由滑动窗口协议保证,而拥塞控制则由控制窗口结合一系列的控制算法实现.一.滑动窗口协议 关于这部分自己不晓得怎么叙述才好,因为理解的部分更多, ...
- 操作系统——CPU、计算机的构成
CPU主要由什么构成? CPU包括运算逻辑部件.寄存器部件和控制部件等. 逻辑部件:可以执行点或浮点算术远算操作.移位操作以及逻辑操作,也可以执行地址运算和转换. 寄存器部件:存储程序.数据和各种信号 ...
- Javascript判断是否是ipad的浏览器
ipad用的是Safari Mobile浏览器,访问的UA为: Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/5 ...
- Android随笔--使用ViewPager实现简单地图片的左右滑动切换
Android中图片的左右切换随处可见,今天我也试着查阅资料试着做了一下,挺简单的一个小Demo,却也发现了一些问题,话不多说,上代码~: 使用了3个xml文件作为ViewPager的滑动page,布 ...
- MySQL修改root密码的几种方法
方法1: 用SET PASSWORD命令 首先登录MySQL. 格式:mysql> set password for 用户名@localhost = password('新密码'); 例子:my ...