Linux 套接字编程 - TCP连接基础

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

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

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

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

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

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

服务端程序:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4
  5 #include <unistd.h>
  6 #include <signal.h>
  7
  8 #include <sys/socket.h>
  9 #include <arpa/inet.h>
 10 #include <netinet/in.h>
 11
 12
 13 #define SOCKET_BACKLOG  100
 14 #define SERVER_PORT     1234
 15 #define BUF_SIZE        256
 16
 17 void echo(int fd);
 18
 19 void setup_signal_handler();
 20
 21 int main() {
 22         /* setup SIGCHLD handler */
 23         setup_signal_handler();
 24
 25         /* define socket address */
 26         struct sockaddr_in server = {0};
 27         server.sin_family = AF_INET;
 28         server.sin_port = htons( SERVER_PORT );
 29
 30
 31         /* define socket file descriptor */
 32         int server_fd = socket(AF_INET, SOCK_STREAM, 0);
 33
 34         /* bind socket file descriptor to the socket address */
 35         bind(server_fd, (struct sockaddr *)&server, sizeof(server));
 36
 37         /* listen on this socket file descriptor */
 38         listen( server_fd, SOCKET_BACKLOG );
 39
 40         /* define socket struct/file descriptor used to present remote peer(client) */
 41         struct sockaddr_in client = {0};
 42         int client_fd;
 43         int client_sockaddr_len = 0;
 44
 45         /* application send buffer */
 46         char buffer[BUF_SIZE];
 47
 48         while (1) {
 49                 printf("server ready to accept\n");
 50                 client_fd = accept(server_fd, (struct sockaddr *)&client, &client_sockaddr_len);
 51                 if (client_fd < 0) {
 52                         /* if SA_RESTART is not set in setup_signal_handler and
 53                          * then when process is interrupted by SIGCHLD
 54                          * the accept() will return EINTR instead of a valid socket fd
 55                          */
 56                         printf("server accept error!\n");
 57                         continue;
 58                 }
 59                 if (fork() == 0) {
 60                         close(server_fd);
 61                         printf("child process start pid(%d)\n", getpid());
 62
 63                         echo(client_fd);
 64
 65                         printf("child process exit  pid(%d)\n", getpid());
 66                         exit(0);
 67                 }
 68                 close(client_fd);
 69         }
 70
 71         return 0;
 72 }
 73
 74 void echo(int fd) {
 75         int n;
 76         char buffer[BUF_SIZE];
 77         while ((n = read(fd, buffer, BUF_SIZE)) > 0) {
 78                 write(fd, buffer, n);
 79         }
 80 }
 81
 82 void signal_child_handler(int signo) {
 83         pid_t pid;
 84         int stat;
 85
 86         /* pid = wait(&stat);
 87          * signal is not queued, many child process exits
 88          * may just cause one signal handle process
 89          * so we should use waitpid() in a row instead of a single wait()
 90          * to collect child process information
 91          */
 92         while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
 93                 printf("child process pid(%d) terminated\n", pid);
 94         }
 95 }
 96
 97 void setup_signal_handler() {
 98         struct sigaction act, old_act;
 99
100         act.sa_handler = signal_child_handler;
101         sigemptyset(&act.sa_mask);
102         act.sa_flags = 0;
103 #ifdef SA_RESTART
104         act.sa_flags |= SA_RESTART;
105         printf("SA_RESTART\n");
106 #endif
107         if (sigaction(SIGCHLD, &act, &old_act) < 0) {
108                 printf("setup SIGCHLD Failed.");
109         }
110 }

客户端程序:

#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, 0);

        struct sockaddr_in server_addr = {0};
        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 0;
}

void send_echo(FILE* fp, int fd) {
        char send_buf[BUF_SIZE] = {0};
        char recv_buf[BUF_SIZE] = {0};

        int readn = 0;
        int writen = 0;

        while(fgets(send_buf, BUF_SIZE, fp) != NULL) {
                if ((writen = write(fd, send_buf, strlen(send_buf) + 1)) < 0) {
                        printf("1st write error\n");
                        break;
                } else {
                        printf("1st write ok\n");
                }

                sleep(1);

                if ((writen = write(fd, "(test)", strlen("(test)") + 1)) < 0) {
                        printf("2nd write error\n");
                        break;
                } else {
                        printf("2nd write ok\n");
                }

                sleep(1);

                if ((readn = read(fd, recv_buf, BUF_SIZE)) < 0) {
                        printf("read error\n");
                        break;
                } else if (readn == 0) {
                        printf("read EOF\n");
                        break;
                }
                fputs(recv_buf, stdout);
        }
        printf("client exit\n");
}

Linux 套接字编程 - TCP连接基础

时间: 2024-08-24 08:31:31

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

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

本文转自IBM博文Linux 套接字编程中的 5 个隐患. “在异构环境中开发可靠的网络应用程序”. Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是开发新手可能会经历一些常见的问题.本文识别一些最常见的隐患并向您显示如何避免它们. 在 4.2 BSD UNIX® 操作系统中首次引入,Sockets API 现在是任何操作系统的标准特性.事实上,很难找到一种不支持 Sockets API 的现代语言.该 API 相当简单,但新的开发人员仍然会遇到一些常

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

下述代码是linux套接字编程的入门代码.分为服务端和客户端源码. 服务端代码的主要流程是绑定ip地址和端口号建立套接字,等待客户端发起访问.接受客户端请求之后,向客户端发送字符串"hello world",关闭套接字,结束程序. 客户端代码的主要流程是向服务端对应的套接字发起请求,读取服务端发送的数据,并且打印出来. 代码已经详细注释,更多细节不再赘述. server.cpp #include<stdio.h> #include<stdlib.h> #incl

Linux 套接字编程 - select

select 可以感知文件表述符集合中的变化,如果办fd0(即标准输入)放入select的read fd set,发现只有按回车的时候select才会返回.查了下要把终端的缓冲大小设为1,这样就能实现击键后马上反应了. #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <termio.h> #include <sys/

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

在异构环境中开发可靠的网络应用程序 M. Tim Jones ([email protected]), 资深软件工程师, Emulex 简介: Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是开发新手可能会经历一些常见的问题.本文识别一些最常见的隐患并向您显示如何避免它们. 发布日期: 2005 年 10 月 08 日 级别: 中级 访问情况 : 13059 次浏览 评论: 0 (查看 | 添加评论 - 登录)  平均分 (34个评分)为本文评分 在

套接字编程--TCP

一.socket编程 socket本身有"插座"的意思,因此用来描述网络连接的一对一关系."在TCP/IP协议中,"TP地址+TCP或端口号"唯一标识网络通讯中的一个进程,"IP地址+端口号"就称为socket.(socket就像当于文件一样,客户端通过往里面写数据,服务器端就从里面读取数据,socket 就是用来做载体的).为TCP/TP协议设计的应用层编程接口称为socketAPI. 二.网络字节序 内存中的多字节数据相对于内存地址

网络 套接字编程 TCP、UDP

网络是大端 发数据从低地址发, 先发的是 高位的数据. 收数据从高位收,先收到的数据存放到低地址. TCP 是 流式的 所用套接字也是流式的 文件描述符 socket 是 IP 加 端口号 用到的函数:         int socket(int domain, int type, int protocol);        int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);        #include <s

Linux套接字编程

网络中的进程是如何通信的? 在网络中进程之间进行通信的时候,那么每个通信的进程必须知道它要和哪个计算机上的哪个进程通信.否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程).这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互. 什么是套接字? 套

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

隐患 1.忽略返回状态 第一个隐患很明显,但它是开发新手最容易犯的一个错误.如果您忽略函数的返回状态,当它们失败或部分成功的时候,您也许会迷失.反过来,这可能传播错误,使定位问题的源头变得困难. 捕获并检查每一个返回状态,而不是忽略它们.考虑清单 1 显示的例子,一个套接字 send 函数. 清单 1. 忽略 API 函数返回状态 int status, sock, mode; /* Create a new stream (TCP) socket */ sock = socket( AF_IN

套接字编程 ---- TCP协议

一.套接字(socket) 套接字socket: ip地址 + port端口号.在TCP/IP协议中,它唯一标识网络通讯中的一个进程. 在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socketpair就唯一标识一个连接. socket本身有"插座"的意思,因此用来描述网络连接的 一对一关系. TCP/IP协议规定,网络数据流应采用 大端字节序,即 (内存)低地址高字节(数据). 二.TCP_SOCKET 相关 TCP 协议  ----