TCP服务器

本次实现一个简单的服务器来了解socket,bind, listen等函数,服务器的主要功能是收到客户端的消息后,原封不动的返回给客户端。

在这里插入代码片
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mytcp.h"

#define LISTENQ 10
#define MAXLINE 1024
int main()
{
    int listenfd, connfd;
    socklen_t len;
    struct sockaddr_in servaddr, cliaddr;
    char buff[MAXLINE];
    pid_t childpid;
    
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(9000);

    if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) {
    	printf("bind error\n");
    }
    if (listen(listenfd, LISTENQ) == -1) {
    	printf("listen error\n");
    }
    printf("bind and listen success\n");
    for(; ;) {
        len = sizeof(cliaddr);
        connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &len);
        if (connfd < 0) {
            printf("accept error\n");
        }
	inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff));
        printf("connection from %s, port %d\n", buff, ntohs(cliaddr.sin_port));
	if ((childpid = fork()) == 0) {
	    close(listenfd);
        str_echo(connfd);
        exit(0);
	}
        close(connfd);
    }
}
在这里插入代码片
通过nc作为客户端来验证
nc 127.0.0.1 9000
123//输入
123//返回

客户端正常退出后,子进程终止 ,并给父进程发送SIGCHLD信号,但是父进程没有捕获处理该信号,会导致僵尸进程的产生。需要在父进程中调用wait或者waitpid来处理。
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
通过注册signal在父进程中捕获SIGCHLD来实现子进程的资源释放。
void sig_child(int signo)
{
    pid_t pid;
    int stat;
    while((pid) = waitpid(-1, &stat, WNOHANG) > 0)
        printf("child %d terminated\n", pid);
    return;
}

改进后的代码如下:

在这里插入代码片
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mytcp.h"

#define LISTENQ 10
#define MAXLINE 1024
int main()
{
    int listenfd, connfd;
    socklen_t len;
    struct sockaddr_in servaddr, cliaddr;
    char buff[MAXLINE];
    pid_t childpid;
    
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(9000);

    if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) {
    	printf("bind error\n");
    }
    if (listen(listenfd, LISTENQ) == -1) {
    	printf("listen error\n");
    }
    printf("bind and listen success\n");
    signal(SIGCHLD, sig_child);
    for(; ;) {
        len = sizeof(cliaddr);
        connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &len);
        if (connfd < 0) {
            printf("accept error\n");
        }
	inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff));
        printf("connection from %s, port %d\n", buff, ntohs(cliaddr.sin_port));
	if ((childpid = fork()) == 0) {
	    close(listenfd);
            str_echo(connfd);
            exit(0);
	}
        close(connfd);
    }
}

同样可以通过nc来模拟客户端查看结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值