UNIX网络编程——使用select函数的TCP和UDP回射服务器程序
服务器程序:
#include <sys/wait.h>
#include <string.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#define SERV_PORT 3334
#define LISTENQ 5
#define MAXLINE 100 void str_echo(int sockfd)
{
ssize_t n;
char buf[MAXLINE]; again:
while ( (n = read(sockfd, buf, MAXLINE)) > 0)
write(sockfd, buf, n); if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
perror("read");
} void sig_chld(int signo)
{
pid_t pid;
int stat; while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
int main(int argc, char **argv)
{
int listenfd, connfd, udpfd, nready, maxfdp1;
char mesg[MAXLINE];
pid_t childpid;
fd_set rset;
ssize_t n;
socklen_t len;
const int on = 1;
struct sockaddr_in cliaddr, servaddr;
void sig_chld(int); /* 4create listening TCP socket */
listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT); setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); listen(listenfd, LISTENQ); /* 4create UDP socket */
udpfd = socket(AF_INET, SOCK_DGRAM, 0); bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT); bind(udpfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
signal(SIGCHLD, sig_chld); /* must call waitpid() */ FD_ZERO(&rset);
maxfdp1 =( (listenfd>udpfd)?listenfd : udpfd ) + 1;
for ( ; ; ) {
FD_SET(listenfd, &rset);
FD_SET(udpfd, &rset);
if ( (nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue; /* back to for() */
else
perror("select");
} if (FD_ISSET(listenfd, &rset)) {
len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &len); if ( (childpid = fork()) == 0) { /* child process */
close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
close(connfd); /* parent closes connected socket */
} if (FD_ISSET(udpfd, &rset)) {
len = sizeof(cliaddr);
n = recvfrom(udpfd, mesg, MAXLINE, 0, (struct sockaddr*) &cliaddr, &len); sendto(udpfd, mesg, n, 0, (struct sockaddr *) &cliaddr, len);
}
}
}
57-67 创建一个监听TCP套接字并捆绑服务器的众所周知的端口,设置SO_REUSEADDR套接字选项以防止该端口上已有连接存在。
70-77 还创建一个UDP套接字并捆绑与TCP套接字相同的端口。这里无需在调用bind之前设置SO_REUSEADDR套接字选项,因为TCP端口是独立于UDP端口的。
78 给SIGCHLD建立信号处理程序,因为TCP连接将由某个子进程处理。
83-90 我们调用select只是为了等待监听TCP套接字的可读条件或UDP套接字的可读条件。既然我们的sig_chld信号处理函数可能中断我们对select的调用,于是我们需要处理EINTR错误。
UNIX网络编程——使用select函数的TCP和UDP回射服务器程序的更多相关文章
- UNIX网络编程——使用select函数编写客户端和服务器
首先看原先<UNIX网络编程--并发服务器(TCP)>的代码,服务器代码serv.c: #include<stdio.h> #include<sys/types.h> ...
- UNIX网络编程——UDP回射服务器程序(初级版本)以及漏洞分析
该函数提供的是一个迭代服务器,而不是像TCP服务器那样可以提供一个并发服务器.其中没有对fork的调用,因此单个服务器进程就得处理所有客户.一般来说,大多数TCP服务器是并发的,而大多数UDP服务器是 ...
- UNIX网络编程读书笔记:图解TCP端口号和并发服务器
图1 TCP服务器在端口21上执行被动打开 图2 客户对服务器的 ...
- 【Unix网络编程】chapter5TCP回射服务器程序
chapter5 5.1 概述 5.2 TCP回射服务器程序:main函数 int main(int argc, char **argv) { int listenfd,connfd; pid_t ...
- 【UNIX网络编程(三)】TCP客户/server程序演示样例
上一节给出了TCP网络编程的函数.这一节使用那些基本函数编写一个完毕的TCP客户/server程序演示样例. 该样例运行的过程例如以下: 1.客户从标准输入读入一行文本,并写给server. 2.se ...
- Linux下select的用法--实现一个简单的回射服务器程序
1.先看man手册 SYNOPSIS /* According to POSIX.1-2001 */ #include <sys/select.h> / ...
- UNIX网络编程——epoll 系列函数简介、与select、poll 的区别
前面博客<<UNIX环境高级编程--epoll函数使用详解>>有关于epoll函数的讲解. 一.epoll 系列函数简介 #include <sys/epoll.h> ...
- 《Unix网络编程》卷一(简介TCP/IP、基础套接字编程)
通常说函数返回某个错误值,实际上是函数返回值为-1,而全局变量errno被置为指定的常值(即称函数返回这个错误值). exit终止进程,Unix在一个进程终止时总是关闭该进程所有打开的描述符. TCP ...
- UNIX网络编程读书笔记:基本TCP套接口编程
编写一个完整的TCP客户和服务器程序所需要的基本套接口函数: 1.socket函数(客户端.服务器端都必须调用) 参数family指明协议族(family),该参数也往往被称为协议域(domain). ...
随机推荐
- mysql的连接处理过程
在mysqld_main函数中经过一系列的初始化后,mysql开始监听客户端的连接 mysqld_socket_acceptor->connection_event_loop(); 查看my ...
- day4 liaoxuefeng---模块
一.模块 二.常用内建模块 三.常用第三方模块
- 设置思科设备console密码、enable密码、vty登录密码
思科设备各级密码:1) console密码 SW2(config)#line console 0SW2(config-line)#password ciscoSW2(config-line)#log ...
- linux安装ftp
安装vsftpd 1.以管理员(root)身份执行以下命令 1. yum install vsftpd 2.设置开机启动vsftpd ftp服务 1. chkconfig vsftpd on 3. ...
- You And Me 不见不散!
泰戈尔说: 有一个夜晚,我烧毁了所有的记忆, 从此我的梦就透明了: 有个早晨我扔掉了所有的昨天, 从此我的脚步就轻盈了! 越过山丘,才发现无人等候! 有段话最近很流行:20多岁的你,迷茫又着急,你想要 ...
- 重新设置Eclipse的workspace路径
有3中方法可以更改workspace的路径设置: 1. 启动Eclipse/MyEclipse后, 打开"Window -> Preferences -> General -&g ...
- 18. 4Sum(中等)
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = tar ...
- C++ 实现俄罗斯方块
C++ 实现俄罗斯方块 一.实验介绍 1.1 实验内容 本节实验我们进行设计俄罗斯方块前的思路分析,以及介绍ncurses 库的使用方法. 1.2 实验知识点 C++ 编程基础 ncurses 库的使 ...
- 05_CRUD操作
1.Params拦截器: 作用:Parameters拦截器将把表单字段映射到ValueStack栈的栈顶对象的各个属性中, 注意:如果某个字段在栈顶对象中没有对应的属性,则Params拦截器将尝试 ...
- 疯狂的Django 之深度外键跨表查找之疯狂INNER JOIN
定义Model: from django.db import models class Moreinfo(models.Model): weight = models.FloatField() hei ...