Linux 套接字编程 - TCP连接基础
第五章的内容,实现一个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连接基础的更多相关文章
- Linux 套接字编程中的 5 个隐患(转)
本文转自IBM博文Linux 套接字编程中的 5 个隐患. “在异构环境中开发可靠的网络应用程序”. Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是开发新 ...
- C++网络套接字编程TCP和UDP实例
原文地址:C++网络套接字编程TCP和UDP实例作者:xiaojiangjiang 1. 创建一个简单的SOCKET编程流程如下 面向有连接的套接字编程 服务器: 1) 创建套接字(so ...
- linux 套接字编程入门--Hello World
下述代码是linux套接字编程的入门代码.分为服务端和客户端源码. 服务端代码的主要流程是绑定ip地址和端口号建立套接字,等待客户端发起访问.接受客户端请求之后,向客户端发送字符串"hell ...
- (转载)Linux 套接字编程中的 5 个隐患
在 4.2 BSD UNIX® 操作系统中首次引入,Sockets API 现在是任何操作系统的标准特性.事实上,很难找到一种不支持 Sockets API 的现代语言.该 API 相当简单,但新的开 ...
- Linux 套接字编程中的 5 个隐患
http://www.ibm.com/developerworks/cn/linux/l-sockpit/ 在 4.2 BSD UNIX® 操作系统中首次引入,Sockets API 现在是任何操作系 ...
- Linux套接字编程
网络中的进程是如何通信的? 在网络中进程之间进行通信的时候,那么每个通信的进程必须知道它要和哪个计算机上的哪个进程通信.否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行 ...
- Linux 套接字编程中要注意的细节
隐患 1.忽略返回状态 第一个隐患很明显,但它是开发新手最容易犯的一个错误.如果您忽略函数的返回状态,当它们失败或部分成功的时候,您也许会迷失.反过来,这可能传播错误,使定位问题的源头变得困难. 捕获 ...
- Linux 套接字编程 - select
select 可以感知文件表述符集合中的变化,如果办fd0(即标准输入)放入select的read fd set,发现只有按回车的时候select才会返回.查了下要把终端的缓冲大小设为1,这样就能实现 ...
- 【转】Linux 套接字编程中的 5 个隐患
地址:请点击这里
随机推荐
- 洛谷P3254 圆桌问题(最大流)
传送门 一道良心啊……没那么多麻烦了…… 从$S$向所有单位连边,容量为单位人数,从所有桌子向$T$连边,容量为桌子能坐的人数,从每一个单位向所有桌子连边,容量为$1$,然后跑一个最大流,看一看$S$ ...
- django 部署到Ubuntu-apache2遇到的问题汇总
1.x86_64-linux-gnu-gcc: error: unrecognized command line option ‘-fstack-protector-strong’ Turns out ...
- 自定义内核启动后的Logo
1.使用图像GIMP工具 2.详细步骤如下: A.将800x480的图片导入到GIMP工具. B.选中GIMP菜单栏进行以下操作 图像 -->模式 ...
- rpm命令-以jenkins为例
1.列出所有安装的Jenkins rpm -qa | grep jenkins 2.软件是否安装:例如:jenkins是否安装 rpm -qa | grep jenkins 3.rpm -ql 列出软 ...
- js自定义对象 (转)
原文地址:https://sjolzy.cn/js-custom-object.html 29 March 2010 9:53 Monday by 小屋 javascript进阶之对象篇 一,概述 在 ...
- python之控制流习题+代码
# !/usr/bin/python3 # -*- coding: utf-8 -*- # @Time :2018/11/26 15:32 # @Author :yosef # @Email :wur ...
- 关于Manjaro与Ubuntu双系统并存引发的一个boot问题
事情发生在写下这篇博客的半小时前.笔者的电脑本身是Manjaro+win10双系统并存,因为一些原因要安装ubuntu. 装完ubuntu用了一阵子,想切回manjaro,于是遇到了这个问题. 看到k ...
- [CSU1911]Card Game(FWT)
[vjudge-CSU1911] FWT_or #include<cstring> #include<iostream> #include<algorithm> # ...
- LeetCode109. 有序链表转换二叉搜索树
109. 有序链表转换二叉搜索树 问题描述 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超 ...
- SPOJ - DQUERY 莫队
题意:给定\(a[1...n]\),\(Q\)次询问,每次统计\([L,R]\)范围内有多少个不同的数字 xjb乱写就A了,莫队真好玩 #include<iostream> #includ ...