【Linux】网络编程pthread/fork

1、查看while源代码

#include <stdlib.h> 
#include <stdio.h> 
#include <errno.h> 
#include <string.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <unistd.h>
#include <arpa/inet.h> 

#define portnumber 3333

int main(int argc, char* argv[]) {
	int local_listen_socket, server_session_socket;
	struct sockaddr_in server_addr_info_struct;
	struct sockaddr_in client_addr_info_struct;
	int size_of_sockaddr_in;
	int read_got_bytes_nr;
	char buffer[1024];


	/* socket: 服务器端开始建立sockfd描述符 */
	if ((local_listen_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { // AF_INET i.e. IPV4; SOCK_STREAM i.e. TCP
		fprintf(stderr, "Socket error:%s\n\a", strerror(errno));
		exit(1);
	}

	/* 准备 sockaddr结构及其内部IP、端口信息 */
	bzero(&server_addr_info_struct, sizeof(struct sockaddr_in)); // 初始化,置0
	server_addr_info_struct.sin_family = AF_INET;                 // Internet
	server_addr_info_struct.sin_addr.s_addr = htonl(INADDR_ANY);  // 将本机host上的long数据转化为网络上的long数据,使服务器程序能运行在不同CPU的主机上 
													// INADDR_ANY 表示主机监听任意/所有IP地址。
	//server_addr_info_struct.sin_addr.s_addr=inet_addr("192.168.1.1");  //用于绑定到一个固定IP,inet_addr用于把数字加格式的ip转化为整形ip
	server_addr_info_struct.sin_port = htons(portnumber);         // (将本机器上的short数据转化为网络上的short数据)端口号

	/* bind: 绑定sockfd描述符 和 IP、端口 */
	if (bind(local_listen_socket, (struct sockaddr*)(&server_addr_info_struct), sizeof(struct sockaddr)) == -1) {
		fprintf(stderr, "ERR bind():%s\n\a", strerror(errno));
		exit(1);
	}

	/* 设置允许连接的最大客户端数 */
	if (listen(local_listen_socket, 5) == -1) {
		fprintf(stderr, "ERR listen():%s\n\a", strerror(errno));
		exit(1);
	}

	while (1) {
		size_of_sockaddr_in = sizeof(struct sockaddr_in);
		fprintf(stderr, "Listening & Accepting...\n");
		if ((server_session_socket = accept(local_listen_socket, (struct sockaddr*)(&client_addr_info_struct), &size_of_sockaddr_in)) == -1) {  // 服务器阻塞, 直到接受到客户连接
			fprintf(stderr, "ERR accept():%s\n\a", strerror(errno));
			exit(1);
		}

		fprintf(stderr, "Got connection from %s\n", inet_ntoa(client_addr_info_struct.sin_addr)); // 网络地址 转换成 字符串
		if ((read_got_bytes_nr = read(server_session_socket, buffer, 1024)) == -1) {
			fprintf(stderr, "ERR read():%s\n", strerror(errno));
			exit(1);
		}
		buffer[read_got_bytes_nr] = '\0';
		printf("Server received %s\n", buffer); /* 这个对话服务已经结束 */
		close(server_session_socket); /* 下一个 */
	}

	/* 结束通讯 */
	close(local_listen_socket);
	exit(0);
}

2、编译并在ubuntu下运行

编译

gcc -o server-while-tcp.out server-while-tcp.c
gcc -o client.out client.c

运行

./server-while-tcp.out
./client.out 192.168.18.128    //新的窗口打开

 3、修改为多线程

server源码

#include <sys/types.h>      /* 网络编程所需头文件*/
#include <sys/socket.h>     /* 网络编程所需头文件*/
#include <string.h>
#include <netinet/in.h>     /* 包含类似inet_ntoa函数的头文件 */
#include <arpa/inet.h>      /* 包含类似inet_ntoa函数的头文件 */
#include <unistd.h>         /* 包含close函数、forck函数等系统调用函数的头文件 */
#include <stdio.h>      
#include <signal.h>         /* 包含signal函数的头文件 */

#define SERVER_PORT 8888        /* 监听端口号 */
#define BACKLOG 10              /* listen函数中最大同时监听连接路数 */

/* socket              
 * bind 
 * listen
 * accept
 * send/recv
*/
int charup(unsigned char ch[1000]);

int main(int argc, char **argv)
{
    int iSocketServer;
    int iSocketClient;
    struct sockaddr_in tSocketServerAddr;   /* 存放服务器端的通讯协议族、要监听的端口号等信息的结构体 */
    struct sockaddr_in tSocketClientAddr;   /* 存放连接的客户端的IP地址等信息的结构体 */
    int iRet;
    int iAddrLen;
        
    int iRecvLen;
    unsigned char ucRecvBuf[1000];

    int iClientNum = -1;

    signal(SIGCHLD, SIG_IGN);     /* 处理僵死进程,如果不加,被关闭的客户端所创建的服务器端子进程的资源将不会被父进程回收,导致资源浪费 */

    iSocketServer = socket(AF_INET, SOCK_STREAM, 0);    /* 创建socket */
    if (-1 == iSocketServer)
    {
        printf("Socket error!\n");
        return -1;
    }

    tSocketServerAddr.sin_family        = AF_INET;
    tSocketServerAddr.sin_port          = htons(SERVER_PORT);   /* 将short型的端口数据转换成适合于网络传输的数据类型 */
    tSocketServerAddr.sin_addr.s_addr   = INADDR_ANY;           /* 允许和任何的主机通信 */
    memset(tSocketServerAddr.sin_zero, 0, 8);                   /* 内存置0,确保和struct sockaddr的长度相同 */
    
    iRet =  bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));  /* 之前创建的socket文件描述符将被bind修饰 */
    if (iRet == -1)
    {
        printf("Bind error!\n");
        return -1;
    }

    iRet = listen(iSocketServer, BACKLOG);      /* 调用listen函数来监听 */
    if (-1 == iRet)
    {
        printf("listen error!\n");
        return -1;
    }
    else
    {
        printf("Listening & Accepting...\n");
    }

    while (1)
    {
        iAddrLen = sizeof(struct sockaddr);
        /* 调用accept函数来等待客户端来连接,客户连接成功返回一个值,连接失败返回-1; */
        iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
        if (-1 != iSocketClient)
        {
            iClientNum++;
            /* 支持多个客户端连接,每有一个就调用fork(),并创建一个子进程 */
            printf("Get connnect from NO.%d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
            if (!fork())                /* 执行到fork()后马上复制一个代码完全一样的子进程*/
            {                           /* 父进程走fork()=0;子进程走fork()!=0; */
                /*子进程的源码*/
                while (1)
                {

                    /* 接受客户端发来的数据并显示出来 */
                    iRecvLen = iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);

                    if (iRecvLen <= 0)            
                    {
                        close(iSocketClient);       /* 一直接受客户端传来的消息 */
                        return -1;
                    }
                    else 
                    {
                        ucRecvBuf[iRecvLen] = '\0';            /* 加上结束符 */
                        printf("Get Msg From client %d : %s\n", iClientNum, ucRecvBuf);
                    }
                    charup(ucRecvBuf);      /* 字符串转大写字母函数 */
                    iRecvLen = send(iSocketClient, ucRecvBuf, strlen(ucRecvBuf), 0);
                    if(iRecvLen <= 0)
                    {
                        close(iSocketClient);
                        return -1;
                    }
                }  
            }
        }
    }
    close(iSocketServer);
    return 0;
}

// 定义字符串转大写字母函数
int charup(unsigned char ch[1000])
{
    int i = 0;
    while (ch[i] != '\0')
    {
        if(ch[i]>='a'&&ch[i]<='z')
        ch[i]=ch[i]-32;  //如果你忘记了大小写之间相差32的值,也可以用'a'-'A'来表示
        i ++;
    }        
    return 0;
}

 client源码

#include <sys/types.h>      /* 网络编程所需头文件*/
#include <sys/socket.h>     /* 网络编程所需头文件*/
#include <string.h>
#include <netinet/in.h>     /* 包含类似inet_ntoa函数的头文件 */
#include <arpa/inet.h>      /* 包含类似inet_ntoa函数的头文件 */
#include <unistd.h>         /* 包含close函数、forck函数等系统调用函数的头文件 */
#include <stdio.h>  
#include <signal.h> 


#define SERVER_PORT 8888                  //同一端口号

/* socket               //系统调用
 * connect 
 * listen
 * send/recv
*/



int main(int argc, char **argv)
{
    int iSocketClient;
    struct sockaddr_in tSocketServerAddr;
        
    int iRet;                  //返回值
    unsigned char ucSendBuf[1000];
    unsigned char ucRecvBuf[1000];
    int iSendLen;
    int iRecvLen;

    if (argc != 2)
    {
        printf("Usage:\n");
        printf("%s <server_ip>\n", argv[0]);
        return -1;
    }

    iSocketClient = socket(AF_INET, SOCK_STREAM, 0);

    tSocketServerAddr.sin_family = AF_INET;
    tSocketServerAddr.sin_port = htons(SERVER_PORT); //host to net,short
    //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;   //本机上所有IP
    if(0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
    {
        printf("invalid server_ip\n");
        return -1;
    }
    memset(tSocketServerAddr.sin_zero, 0 , 8);

    iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
    if (-1 == iRet)
    {
        printf("connect error!\n");
        printf("%s <server_ip>\n", argv[0]);
        return -1;
    }

    while (1)
    {
        if(fgets(ucSendBuf, 999, stdin))
        {
            iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
            if(iSendLen <= 0)
            {
                close(iSocketClient);
                return -1;
            }  
        }  
        iRecvLen = iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
        if (iRecvLen <= 0)            
        {
            close(iSocketClient);       //一直接受客户端传来的消息
            return -1;
        }
        else 
        {
            ucRecvBuf[iRecvLen] = '\0';            //加上结束符
            printf("Feedback:%s\n", ucRecvBuf);
        }
    }
    return 0;
}

 编译

gcc -o srv srv.c
gcc -o cli cli.c

运行

./srv
./cli 192.168.18.128    //新的窗口打开

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值