第五章的内容,实现一个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. hadoop计算二度人脉关系推荐好友

    https://www.jianshu.com/p/8707cd015ba1 问题描述: 以下是qq好友关系,进行好友推荐,比如:老王和二狗是好友 , 二狗和春子以及花朵是好友,那么老王和花朵 或者老 ...

  2. Eclipse中文件夹变成包的解决办法(python版)

    问题展示如下: 如图,框中的三个文件夹都变成了包的样子. 解决方法如下: 1.在项目文件夹上右键,打开属性框 2.将PYTHONPATH中,Source Folders中的文件夹都删除.即可看到包已变 ...

  3. javascript阻止事件冒泡的方法

    有的时候我们需要实现这样的功能: 点击某个蒙版,该蒙版消失,但是如果点击蒙版上的某个元素,希望蒙版不消失,这就需要用到阻止事件的冒泡了 html: <div id="outer&quo ...

  4. 批量改ID 行形式

    update [Temp_Sql] set ID(字段) = (274+ID(字段))  字段+字段形式 可以以行形式批量修改

  5. JUC包下Semaphore学习笔记

    在Java的并发包中,Semaphore类表示信号量.Semaphore内部主要通过AQS(AbstractQueuedSynchronizer)实现线程的管理.Semaphore有两个构造函数,参数 ...

  6. python学习之路---day06

    一:is 和 == 的区别 01)a b 两个变量 is 是比较变量的内存地址,如果地址相等,则返回True,如果不相等,则返回False == 是比较变量两边内容是否一样,如果一样则返回True,不 ...

  7. 编写高质量代码:Web前端开发修炼之道(一)

    最近老大给我们买来一些技术方面的书籍,其实很少搬着一本书好好的完整的看完过,每每看电子档的,也是打游击式的看看这章,瞅瞅那章,在那5本书中挑了一本比较单薄的<编写高质量代码web前端开发修炼之道 ...

  8. FFMpeg 版本错误

    错误情况: relocation error: /usr/local/lib/libavfilter.so.3: symbol sws_get_class, version LIBSWSCALE_2 ...

  9. PIE SDK地图范围设置和图层事件监听

    1. 功能简介 地图范围设置的监听就是通过IMapControlEvents接口对地图的视图范围更新或者地图的分辨率发生变化进行监听,然后做出相应的操作. 图层事件的监听就是通过IActiveView ...

  10. PIE SDK算法的自定义扩展

    1.算法功能简介 算法的自定义扩展允许用户自主开发新的算法.自定义的算法必须实现PIE.SystemAlgo.BaseSystemAlgo基础类,这样才能被PIE的算法管理器调用起来. 2.算法功能实 ...