第五章的内容,实现一个echo服务器和对应的客户端,主要收获:

0. TCP socket编程主要基本步骤

1. SIGCHLD信号含义(子进程退出时向父进程发送,提醒父进程对其状态信息进行一个获取),waitpid 和 wait在使用上的差异,前者可以配置参数设定为非阻塞方式调用,更加灵活。

2. 信号处理函数与其过程(尤其是信号发生后不列队这个性质),相同的信号多次发生(间隔非常接近的话)可能仅会调用一次信号处理函数

3. 信号处理对慢系统(阻塞)调用如accept等的影响(如果信号处理设置时没有置SA_RESTART),accept被中断后直接返回EINTR,而不是一个合法的socket fd,所以对一些调用的错误值检测并不是杞人忧天

4. 僵尸进程,只要父进程调用了wait*函数获取了已死子进程的状态信息后,它就消失了。但如果父进程产生了超多子进程,而他们有很快的死掉,然后父进程也不调用wait*函数,那么会使得pid号不够用

服务端程序:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <unistd.h>
#include <signal.h> #include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h> #define SOCKET_BACKLOG 100
#define SERVER_PORT 1234
#define BUF_SIZE 256 void echo(int fd); void setup_signal_handler(); int main() {
/* setup SIGCHLD handler */
setup_signal_handler(); /* define socket address */
struct sockaddr_in server = {};
server.sin_family = AF_INET;
server.sin_port = htons( SERVER_PORT ); /* define socket file descriptor */
int server_fd = socket(AF_INET, SOCK_STREAM, ); /* bind socket file descriptor to the socket address */
bind(server_fd, (struct sockaddr *)&server, sizeof(server)); /* listen on this socket file descriptor */
listen( server_fd, SOCKET_BACKLOG ); /* define socket struct/file descriptor used to present remote peer(client) */
struct sockaddr_in client = {};
int client_fd;
int client_sockaddr_len = ; /* application send buffer */
char buffer[BUF_SIZE]; while () {
printf("server ready to accept\n");
client_fd = accept(server_fd, (struct sockaddr *)&client, &client_sockaddr_len);
if (client_fd < ) {
/* if SA_RESTART is not set in setup_signal_handler and
* then when process is interrupted by SIGCHLD
* the accept() will return EINTR instead of a valid socket fd
*/
printf("server accept error!\n");
continue;
}
if (fork() == ) {
close(server_fd);
printf("child process start pid(%d)\n", getpid()); echo(client_fd); printf("child process exit pid(%d)\n", getpid());
exit();
}
close(client_fd);
} return ;
} void echo(int fd) {
int n;
char buffer[BUF_SIZE];
while ((n = read(fd, buffer, BUF_SIZE)) > ) {
write(fd, buffer, n);
}
} void signal_child_handler(int signo) {
pid_t pid;
int stat; /* pid = wait(&stat);
* signal is not queued, many child process exits
* may just cause one signal handle process
* so we should use waitpid() in a row instead of a single wait()
* to collect child process information
*/
while ((pid = waitpid(-, &stat, WNOHANG)) > ) {
printf("child process pid(%d) terminated\n", pid);
}
} void setup_signal_handler() {
struct sigaction act, old_act; act.sa_handler = signal_child_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = ;
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
printf("SA_RESTART\n");
#endif
if (sigaction(SIGCHLD, &act, &old_act) < ) {
printf("setup SIGCHLD Failed.");
}
}

客户端程序:

#include <unistd.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h> #include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h> #define SERVER_PORT 1234
#define SERVER_IP "127.0.0.1" #define BUF_SIZE 256 void send_echo(FILE* fp, int fd); int main() {
int sockfd = socket(AF_INET, SOCK_STREAM, ); struct sockaddr_in server_addr = {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT); inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr); connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); send_echo(stdin, sockfd); return ;
} void send_echo(FILE* fp, int fd) {
char send_buf[BUF_SIZE] = {};
char recv_buf[BUF_SIZE] = {}; int readn = ;
int writen = ; while(fgets(send_buf, BUF_SIZE, fp) != NULL) {
if ((writen = write(fd, send_buf, strlen(send_buf) + )) < ) {
printf("1st write error\n");
break;
} else {
printf("1st write ok\n");
} sleep(); if ((writen = write(fd, "(test)", strlen("(test)") + )) < ) {
printf("2nd write error\n");
break;
} else {
printf("2nd write ok\n");
} sleep(); if ((readn = read(fd, recv_buf, BUF_SIZE)) < ) {
printf("read error\n");
break;
} else if (readn == ) {
printf("read EOF\n");
break;
}
fputs(recv_buf, stdout);
}
printf("client exit\n");
}

Linux 套接字编程 - TCP连接基础的更多相关文章

  1. Linux 套接字编程中的 5 个隐患(转)

    本文转自IBM博文Linux 套接字编程中的 5 个隐患. “在异构环境中开发可靠的网络应用程序”. Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是开发新 ...

  2. C++网络套接字编程TCP和UDP实例

    原文地址:C++网络套接字编程TCP和UDP实例作者:xiaojiangjiang 1.       创建一个简单的SOCKET编程流程如下 面向有连接的套接字编程 服务器: 1)  创建套接字(so ...

  3. linux 套接字编程入门--Hello World

    下述代码是linux套接字编程的入门代码.分为服务端和客户端源码. 服务端代码的主要流程是绑定ip地址和端口号建立套接字,等待客户端发起访问.接受客户端请求之后,向客户端发送字符串"hell ...

  4. (转载)Linux 套接字编程中的 5 个隐患

    在 4.2 BSD UNIX® 操作系统中首次引入,Sockets API 现在是任何操作系统的标准特性.事实上,很难找到一种不支持 Sockets API 的现代语言.该 API 相当简单,但新的开 ...

  5. Linux 套接字编程中的 5 个隐患

    http://www.ibm.com/developerworks/cn/linux/l-sockpit/ 在 4.2 BSD UNIX® 操作系统中首次引入,Sockets API 现在是任何操作系 ...

  6. Linux套接字编程

    网络中的进程是如何通信的? 在网络中进程之间进行通信的时候,那么每个通信的进程必须知道它要和哪个计算机上的哪个进程通信.否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行 ...

  7. Linux 套接字编程中要注意的细节

    隐患 1.忽略返回状态 第一个隐患很明显,但它是开发新手最容易犯的一个错误.如果您忽略函数的返回状态,当它们失败或部分成功的时候,您也许会迷失.反过来,这可能传播错误,使定位问题的源头变得困难. 捕获 ...

  8. Linux 套接字编程 - select

    select 可以感知文件表述符集合中的变化,如果办fd0(即标准输入)放入select的read fd set,发现只有按回车的时候select才会返回.查了下要把终端的缓冲大小设为1,这样就能实现 ...

  9. 【转】Linux 套接字编程中的 5 个隐患

    地址:请点击这里

随机推荐

  1. The server of Nginx(一)——Nginx基础及静态网站的构建

    一.Nginx介绍 火了半边天的Nginx和Apache一样也是Web服务器,专为性能优化而开发,也可以像Squid一样做反向代理,或者邮件代理等许多用途,并有windows的移植版,其最知名的优点是 ...

  2. css文章

    前端HTML-CSS规范:https://yq.aliyun.com/articles/51487 jQuery+d3绘制流程图:https://blog.csdn.net/zitong_ccnu/a ...

  3. ajax beforeSend中无效果

    asnyc:false 与beforesend 同时使用 无效果

  4. 创建React工程

    下载 main.jsBundle 包curl http://localhost:8081/index.ios.bundle -o main.jsbundle <!DOCTYPE html> ...

  5. 20165224 陆艺杰 Exp4 恶意代码分析

    Exp4 恶意代码分析 1实验后回答问题 (1)如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些,用什么方法来监控. 计划任务每段 ...

  6. ELK (Elasticsearch , Logstash, Kibana [+FileBeat])

    ELK 简述: ELK 是: Elasticsearch , Logstash, Kibana 简称, 它们都是开源软件. Elasticsearch[搜索]是个开源分布式基于Lucene的搜索引擎, ...

  7. C++_类入门2-使用类

    进一步探讨类的特征,重点是类设计技术,而不是通用原理.一些特性很容易,一些特性很微妙. 运算符重载 目的是使C++操作更美观,更接近于内置类型的操作. 隐藏了内部的实现机理,并强调了实质. 格式:op ...

  8. spark java wordCount实例

    1. 算子 package com.test; import java.util.Arrays; import java.util.List; import org.apache.spark.Spar ...

  9. PIE SDK地图图层渲染方案管理

    1. 功能简介 在数据种类较多.渲染规则复杂的情况下,逐个设置其渲染方式是一件繁琐的工作.PIE SDK提供了一种省力省心的办法, PIE SDK提供栅格和矢量数据渲染方案的打开与保存.能够将配色方案 ...

  10. nginx-图片资源代理

    location ~ .*\.(gif|jpg|jpeg|png|bmp|mp3)$ { root E:/xx/Uploads/; } 记得放在根目录下面