服务端:

//回射服务器
//避免僵尸进程
#include "unistd.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "sys/wait.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include "stdlib.h"
#include "stdio.h"
#include "errno.h"
#include "string.h"
#include "signal.h" #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while() ssize_t readn(int fd , void *buf, size_t count)
{
size_t nleft = count; //剩余字节数 //在32位系统中size_t是4字节的,而在64位系统中,size_t是8字节的 增加可移植性
ssize_t nread;//读到的字节数 //ssize_t:这个数据类型用来表示可以被执行读写操作的数据块的大小,它表示的是sign size_t类型的。
char *bufp = (char*)buf; while (nleft > )
{
if ((nread = read(fd , bufp ,nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nread == ) //对等方关闭
return count - nleft;
bufp += nread;
nleft -= nread;
}
return count;
} ssize_t writen(int fd , const void *buf , size_t count)
{
size_t nleft = count; //剩余字节数
ssize_t nwritten;
char *bufp = (char*)buf; while (nleft > )
{
if ((nwritten = write(fd , bufp ,nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nwritten == ) //对等方关闭
continue;
bufp += nwritten;
nleft -= nwritten;
}
return count;
} ssize_t recv_peek(int sockfd , void *buf , size_t len)
{
while ()
{
int ret = recv(sockfd , buf , len , MSG_PEEK);
if (ret == - && errno == EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd , void *buf , size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while ()
{
ret = recv_peek(sockfd , bufp , nleft);
if (ret < )
return ret;
else if (ret == )
return ret;
nread = ret;
int i;
for (i=;i<nread;i++)
{
if (bufp[i] == '\n')
{
ret = readn(sockfd,bufp,i+); // i+1 包括 \n
if (ret != i + )
exit(EXIT_FAILURE);
return ret;
}
}
if (nread > nleft)
exit(EXIT_FAILURE);
nleft -= nread;
ret = readn(sockfd , bufp , nread);
if (ret != nread)
exit(EXIT_FAILURE);
bufp += nread;
}
return -; //运行到这里就出错了
} void echo_srv(int conn)
{
char recvbuf[];
int n;
while()
{
memset(&recvbuf,,sizeof(recvbuf));
int ret = readline(conn,recvbuf,);
//扑捉客户端关闭
if (ret == -)
ERR_EXIT("readline");
if (ret == )
{
printf("clientclose\n");
break;
}
fputs(recvbuf,stdout);
writen(conn,recvbuf,strlen(recvbuf));
}
} void handle_sigchld(int sig)
{
// wait(NULL);
while (waitpid(-,NULL,WNOHANG) > );//waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。
} int main(int argc, char const *argv[])
{
// signal(SIGCHLD,SIG_IGN);//避免僵尸进程
signal(SIGCHLD,handle_sigchld);//避免僵尸进程
int listenfd;
if ((listenfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < ) //IPv4为PF_INET,IPv6为PF_INET6;TCP传输时为SOCK_STREAM, UDP位SOCK_DGRAM
ERR_EXIT("socket");
struct sockaddr_in servaddr;
memset(&servaddr,,sizeof(servaddr));
servaddr.sin_family = AF_INET; //设置地址家族 协议族,在socket编程中只能是AF_INET
servaddr.sin_port = htons(); //设置端口
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //设置地址
// servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
// inet_aton("127.0.0.1",&servaddr.sin_addr); int on = ;
if (setsockopt(listenfd, SOL_SOCKET , SO_REUSEADDR, &on , sizeof(on)) < )//setsockopt()函数,用于任意类型、任意状态套接口的设置选项值。
ERR_EXIT("setsockopt"); if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < )
ERR_EXIT("bind");
/*定义函数:int bind(int sockfd, struct sockaddr * my_addr, int addrlen);
函数说明:bind()用来设置给参数sockfd 的socket 一个名称. 此名称由参数my_addr 指向一sockaddr 结构,对于不同的socket domain 定义了一个通用的数据结构
*/
if (listen(listenfd,SOMAXCONN) < )
ERR_EXIT("listen"); struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int conn; // pid_t pid;
// while (1)
// {
// if ((conn = accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen)) < 0)
// ERR_EXIT("accept");
// /*
// 定义函数:int accept(int s, struct sockaddr * addr, int * addrlen);
// 函数说明:accept()用来接受参数s 的socket 连线. 参数s 的socket 必需先经bind()、listen()函数处理过,
// 当有连线进来时accept()会返回一个新的socket 处理代码, 往后的数据传送与读取就是经由新的socket处理,
// 而原来参数s 的socket 能继续使用accept()来接受新的连线要求. 连线成功时, 参数addr
// 所指的结构会被系统填入远程主机的地址数据, 参数addrlen 为scokaddr 的结构长度. 关于机构sockaddr 的定义请参考bind().
// */
// printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr) , ntohs(peeraddr.sin_port));
// //inet_ntoa 将网络地址转换成“.”点隔的字符串格式。
// //ntohs 本函数将一个16位数由网络字节顺序转换为主机字节顺序。
//
// pid = fork();
// if (pid == -1)
// ERR_EXIT("fork");
// if (pid == 0)
// {
// close(listenfd);
// echo_srv(conn);
// exit(EXIT_SUCCESS);
// }else
// close(conn);
// } int client[FD_SETSIZE];//保存客户端文件描述符
int maxi = ;
int i;
for(i= ; i < FD_SETSIZE;i++)
client[i] = -; int nready;
int maxfd = listenfd;
fd_set rset;
fd_set allset;
FD_ZERO(&rset);
FD_ZERO(&allset);
FD_SET(listenfd,&allset);
while ()
{
rset = allset;
nready = select(maxfd+,&rset,NULL,NULL,NULL);
if (nready == -)
{
if (errno == EINTR)
continue;
ERR_EXIT("select");
}
if (nready == )
continue;
if (FD_ISSET(listenfd,&rset))
{
peerlen = sizeof(peeraddr);
conn = accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen);
if (conn == -)
ERR_EXIT("accept");
for (i=;i<FD_SETSIZE;i++)
{
if (client[i] < )
{
client[i] = conn;
if (i > maxi)
maxi = i;
break;
}
}
if (i == FD_SETSIZE)
{
fprintf(stderr,"too many clients\n");
exit(EXIT_FAILURE);
}
printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr) , ntohs(peeraddr.sin_port));
FD_SET(conn,&allset);
if (conn > maxfd)
maxfd = conn; if (--nready <= )
continue;
} for(i=;i<=maxi;i++)
{
conn = client[i];
if (conn == -)
continue;
if (FD_ISSET(conn,&rset))
{
char recvbuf[] = {};
int ret = readline(conn,recvbuf,);
//扑捉客户端关闭
if (ret == -)
ERR_EXIT("readline");
if (ret == )
{
printf("clientclose\n");
FD_CLR(conn,&allset);
client[i] = -;
}
fputs(recvbuf,stdout);
writen(conn,recvbuf,strlen(recvbuf)); if (--nready <= )
break;
}
}
}
return ;
}

客户端:

//回射客户端

#include "unistd.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include "stdlib.h"
#include "stdio.h"
#include "errno.h"
#include "string.h"
#include "signal.h" #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while() ssize_t readn(int fd , void *buf, size_t count)
{
size_t nleft = count; //剩余字节数
ssize_t nread;//读到的字节数
char *bufp = (char*)buf; while (nleft > )
{
if ((nread = read(fd , bufp ,nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nread == ) //对等方关闭
return count - nleft;
bufp += nread;
nleft -= nread;
}
return count;
} ssize_t writen(int fd , const void *buf , size_t count)
{
size_t nleft = count; //剩余字节数
ssize_t nwritten;
char *bufp = (char*)buf; while (nleft > )
{
if ((nwritten = write(fd , bufp ,nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nwritten == ) //对等方关闭
continue;
bufp += nwritten;
nleft -= nwritten;
}
return count;
} ssize_t recv_peek(int sockfd , void *buf , size_t len)
{
while ()
{
int ret = recv(sockfd , buf , len , MSG_PEEK);
if (ret == - && errno == EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd , void *buf , size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while ()
{
ret = recv_peek(sockfd , bufp , nleft);
if (ret < )
return ret;
else if (ret == )
return ret;
nread = ret;
int i;
for (i=;i<nread;i++)
{
if (bufp[i] == '\n')
{
ret = readn(sockfd,bufp,i+); // i+1 包括 \n
if (ret != i + )
exit(EXIT_FAILURE);
return ret;
}
}
if (nread > nleft)
exit(EXIT_FAILURE);
nleft -= nread;
ret = readn(sockfd , bufp , nread);
if (ret != nread)
exit(EXIT_FAILURE);
bufp += nread;
}
return -; //运行到这里就出错了
} void echo_cli(int sock)
{
// char sendbuf[1024] = {0};
// char recvbuf[1024] = {0};
// while (fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)
// {
// writen(sock,sendbuf,strlen(sendbuf)); //包头加包体
// int ret = readline(sock ,recvbuf,sizeof(recvbuf));
// //扑捉客户端关闭
// if (ret == -1)
// ERR_EXIT("readline");
// else if (ret == 0)
// {
// printf("client close\n");
// break;
// }
// fputs(recvbuf,stdout);
// memset(sendbuf , 0 , sizeof(sendbuf));
// memset(recvbuf , 0 , sizeof(recvbuf));
// }
// close(sock);
fd_set rset;
FD_ZERO(&rset); int nready;
int maxfd;
int fd_stdin = fileno(stdin);
if (fd_stdin > sock)
maxfd = fd_stdin;
else
maxfd = sock; char sendbuf[] = {};
char recvbuf[] = {};
while ()
{
FD_SET(fd_stdin,&rset);
FD_SET(sock,&rset);
nready = select(maxfd+,&rset,NULL,NULL,NULL);
if (nready == -)
ERR_EXIT("select");
if (nready == )
continue;
if (FD_ISSET(sock,&rset))
{
int ret = readline(sock ,recvbuf,sizeof(recvbuf));
//扑捉客户端关闭
if (ret == -)
ERR_EXIT("readline");
else if (ret == )
{
printf("server close\n");
break;
}
fputs(recvbuf,stdout);
memset(recvbuf , , sizeof(recvbuf));
} if (FD_ISSET(fd_stdin,&rset))
{
if (fgets(sendbuf,sizeof(sendbuf),stdin) == NULL)
break;
writen(sock,sendbuf,strlen(sendbuf));
memset(sendbuf,,sizeof(sendbuf));
}
}
close(sock); } void handle_sigpipe(int sig)
{
printf("recv a sig=%d\n",sig);
} int main(void)
{
signal(SIGPIPE,handle_sigpipe);
int sock;
if ((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < ) //IPv4为PF_INET,IPv6为PF_INET6;TCP传输时为SOCK_STREAM, UDP位SOCK_DGRAM
ERR_EXIT("socket");
struct sockaddr_in servaddr;
memset(&servaddr,,sizeof(servaddr));
servaddr.sin_family = AF_INET; //设置地址家族
servaddr.sin_port = htons(); //设置端口
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //设置地址 if (connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < )
ERR_EXIT("connect"); struct sockaddr_in localaddr;
socklen_t addrlen = sizeof(localaddr);
if (getsockname(sock , (struct sockaddr*)&localaddr , &addrlen) < )
ERR_EXIT("getsockname");
printf("ip=%s port=%d\n", inet_ntoa(localaddr.sin_addr) , ntohs(localaddr.sin_port));
echo_cli(sock);
return ;
}

linux网络编程:使用单进程实现多客户端通信的更多相关文章

  1. java网络编程-单线程服务端与客户端通信

    该服务器一次只能处理一个客户端请求;p/** * 利用Socket进行简单服务端与客户端连接 * 这是服务端 */public class EchoServer { private ServerSoc ...

  2. Linux网络编程(六)

    网络编程中,使用多路IO复用的典型场合: 1.当客户处理多个描述字时(交互式输入以及网络接口),必须使用IO复用. 2.一个客户同时处理多个套接口. 3.一个tcp服务程序既要处理监听套接口,又要处理 ...

  3. Linux网络编程(五)

    /*Linux网络编程(五)——多路IO复用之select() 网络编程中,使用IO复用的典型场合: 1.当客户处理多个描述字时(交互式输入以及网络接口),必须使用IO复用. 2.一个客户同时处理多个 ...

  4. 【linux草鞋应用编程系列】_5_ Linux网络编程

    一.网络通信简介   第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章.   二.linux网络通信     在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...

  5. linux网络编程-(socket套接字编程UDP传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  6. linux网络编程_1

    本文属于转载,稍有改动,以利于学习. (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...

  7. Linux网络编程入门 (转载)

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  8. [转] - Linux网络编程 -- 网络知识介绍

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  9. Linux C 程序 Linux网络编程(21)

    Linux网络编程网络编程必备的理论基础网络模型,地址,端口,TCP/IP协议 TCP/IP协议是目前世界上使用最广泛的网络通信协议日常中的大部分应用使用该系列协议(浏览网页,收发电子邮件,QQ聊天等 ...

  10. 【转】Linux网络编程入门

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

随机推荐

  1. (原)mkl用到的函数

    转载请注明出处: http://www.cnblogs.com/darkknightzh/p/5585301.html 计算 $C=\alpha *A*B+\beta *C$: void cblas_ ...

  2. 给Array添加删除重复元素函数

    给Array本地对象增加一个原型方法,它用于删除数组中重复的元素(可能有多个重复), 返回值是一个包含被删除的重复条目的新数组. Array.prototype.distinct = function ...

  3. vs2010中自动实现抽象方法

    由于刚接触vs,感官上虽然和eclipse差不多,但是一些快捷都不太相同,导致一开始使用时候非常不习惯. 不过刚开始嘛,写点相当小白的东西,也没有用到太多功能,也就暂时忽视,用的时候再说. 但是今天, ...

  4. 关于《Cocos2d-x建工程时避免copy文件夹和库》的更新

    在前几篇博文中大概了解了Cocos2d-x引擎的基本结构后打算开始实际操作,便在网上转载了一篇关于VS新建Cocos2d-x项目的文章.今天实际操作的时候发现博主使用的引擎版本和我的不一致(<C ...

  5. j2ee中request.getQueryString()

    比如发送http://localhost/test.do?a=b&c=d&e=f得到的是a=b&c=d&e=f

  6. sql中插入多条记录-微软批处理

    这是使用批处理的一个例子: System.IO.StreamWriter messagelog = null; string messageString = ""; SqlConn ...

  7. Win 10 、Win 8 系统默认字体如何修改为宋体

    Win 10 字体改为宋体方法:新建一个文本文档txt,将如下代码复制进去:Windows Registry Editor Version 5.00[HKEY_LOCAL_MACHINE\SOFTWA ...

  8. PASCAL的优越性:官方的说法(不需要Makefile,节约大量的时间)

    也许你认为为什么我选择pascal代替其他的语言,像C.或者您会拿FreePascal和其他的pascal编译器作比较,那么好,这里您看看FreePascal为什么好: 1.pascal是一个非常简洁 ...

  9. Window运行命令大全

    1. gpedit.msc-----组策略    2. sndrec32-------录音机   3. Nslookup-------IP地址侦测器   4. explorer-------打开资源管 ...

  10. C# 委托2

    委托的定义: (1) 将方法作为变量使用的一种机制,就是将方法当作变量用(声明,赋值,传参)   (2) 将变量当作方法来用,首先就要去声明变量,就要考虑变量的类型,就是(委托变量,对应方法的返回值, ...