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 个隐患
地址:请点击这里
随机推荐
- js闭包引起的事件注册问题
背景:闲暇时间看了几篇关于js作用域链与闭包的文章,偶然又看到了之前遇到的一个问题,就是在for循环中为dom节点注册事件驱动,具体见下面代码: <!DOCTYPE html> <h ...
- 【guava】对象处理
一,equals方法 我们在开发中经常会需要比较两个对象是否相等,这时候我们需要考虑比较的两个对象是否为null,然后再调用equals方法来比较是否相等,google guava库的com.goog ...
- 【spring】bean加载顺序
问题来源 有一个bean为A,一个bean为B.想要A在容器实例化的时候的一个属性name赋值为B的一个方法funB的返回值. 如果只是在A里单纯的写着: private B b; private S ...
- logging、hashlib、collections模块
一.hashlib模块(加密模块) 1.什么叫hash:hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 , ...
- Python——requests的安装及入门-贴吧爬虫
一.windows平台下requests的安装 1.win+R,输入cmd,打开命令行窗口,输入命令:pip install requests ,即可自动安装库成功 2.输入命令:pip list,即 ...
- Python获取网页Html文本
Python爬虫基础 1.获取网页文本 通过urllib2包,根据url获取网页的html文本内容并返回 #coding:utf-8 import requests, json, time, re, ...
- 在VS 2012或2013中使用WSE
1,首先下载 WSE http://www.microsoft.com/en-us/download/confirmation.aspx?id=14089 2,安装的时候选上, 3,C:\Progra ...
- java基础_01
一.java中的数据类型 1.基本数据类型:四类八种 byte(1),boolean(1),short(2),char(2),int(4),float(4),long(8),double(8); 2. ...
- WebStorm ES6 语法支持设置和ES6语法的JS文件编译为ES5语法文件
ECMAScript 6是JavaScript语言的下一代标准,已经在2015年6月正式发布了.Mozilla公司将在这个标准的基础上,推出JavaScript 2.0.ES6的目标,是使得JavaS ...
- 20多个常用的免费WebService接口
20多个常用的免费WebService接口 天气预报Web服务,数据来源于中国气象局 Endpoint Disco WSDL IP地址来源搜索 WEB 服务(是目前最完整的IP地址数据) Endp ...