linux-socket编程(二)

1:TCP客户/服务器模型(c/s)

    

这个就是建立连接的过程。图片摘自https://www.bilibili.com/video/BV1eb411F74G?p=7

2:回射客户/服务器模型

3:socket, bind, listen, accept, connect

实现上面所示的功能,需要的函数:

socket函数

//socket函数

/*
	包含头文件:<sys/socket.h> 
	功能:创建一个套接字用于通信 
	原型:
		int socket(int domain, int type, int protocol);  
	参数:
		domain:指定通信协议族(protocol family)
		type:指定socket类型,流式套接字SOCK_STREAM,
		      数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW 
		protocol:协议类型
	返回值:
		成功返回非负整数,它与文件描述符类似,称其为套接字描述字,
		简称套接字。失败返回-1	
*/ 

  在使用的时候可以使用man 函数名来查看使用方式,和选取合适的参数。例如 man socket:

bind函数

//bind函数

/*
    包含头文件<sys/socket.h>
    功能:绑定一个本地地址到套接字
    原型:
        int bind(itn sockfd, const struct sockaddr *addr, socklen_t addrlen);
    参数:
        sockfd: socket函数返回的套接字
        addr:要绑定的地址
        addrlen: 地址长度
    返回值:成功返回0,失败返回-1; 
*/ 

listen函数

//listen函数

/*
	包含头文件<sys/socket.h>
	功能:将套接字用于监听进入的连接 
	原型:
		int listen(itn sockfd, int backlog);
	参数:
		sockfd: socket函数返回的套接字。 
		backlog: 规定内核为此套接字排队的最大连接个数。规定了并发的连接数 
	返回值:成功返回0,失败返回-1;
*/ 

在这里涉及到了两种套接字,分别为被动套接字和主动套接字,listen函数是将主动套接字变为被动套接字。listen函数应该在调用socket和bind函数之后,调用函数accept之前调用。

对于给定的监听套接口,内核要维护两个队列:

       已由客户发出并到达服务器,服务器正在等待完成相应的TCP三次握手过程:

       已完成连接的的队列。(在accept以后就会被移除该队列,一遍更多的客户进来)

accept函数

//accept函数

/*
	含头文件<sys/socket.h>
		功能:从已完成连接队列返回第一个连接,如果已完成连接队列为空,则阻塞。 
		原型:
			int accept(int sockfd, struct sockadder *addr, socklen_t *addrlen);
		参数:
			sockfd: 服务器套接字。 
			addr: 将返回对等方的套接字地址
			addrlen: 返回对等方的套接字地址长度。 
		返回值:成功返回非负整数,失败返回-1;

*/ 

connect函数

//connect函数

/*
	含头文件<sys/socket.h>
		功能:建立一个连接至addr所指定的套接字 
		原型:
			int connect(int sockfd, const struct sockadder *addr, socklen_t addrlen);
		参数:
			sockfd: 为连接套接字。 
			addr: 要连接的套接字地址 
			addrlen: 第二个参数addr长度。 
		返回值:成功返回0,失败返回-1;
*/  

回射客户/服务器模型例子:

服务端程序:

include <iostream>
#include <stdio.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>

using namespace std;

#define ERR_EXIT(m) \
        do \
        { \
                perror(m); \
                exit(EXIT_FAILURE); \
        }while(0);

int main()
{
        //创建套接字
        int creat_socket;
        creat_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(creat_socket < 0)
        {
        ERR_EXIT("socket");
        }


        //分配套接字地址
        struct sockaddr_in servaddr;
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET; //表示使用的IPV4
        servaddr.sin_port = htons(3453);
        //servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_addr.s_addr = inet_addr("192.168.204.131");   

        //绑定套接字地址
        if( bind(creat_socket, (struct sockaddr*)&servaddr, sizeof(servaddr) ) < 0 )
        {
                ERR_EXIT("bind");
        }


        //等待连接请求状态
        if( listen(creat_socket,SOMAXCONN) < 0 )
        {
                     ERR_EXIT("listen");
        }

        //允许连接
        struct sockaddr_in linkaddr;
        socklen_t linklen = sizeof(linkaddr);
        int conn = accept(creat_socket, (struct sockaddr *)&linkaddr, &linklen);
        if(conn < 0)
        {
                ERR_EXIT("accept");
        }


        //输出连接到的IP地址和端口号
        printf("id = %s ,", inet_ntoa(linkaddr.sin_addr));
        printf("port = %d\n", ntohs(linkaddr.sin_port));

        //数据交换
        char recvbuf[1024];
        while(1)
        {
                memset(recvbuf,0,sizeof(recvbuf));
                int ret = read(conn,recvbuf, sizeof(recvbuf));
                fputs(recvbuf,stdout);
                write(conn, recvbuf, ret);
                memset(recvbuf, 0, sizeof(recvbuf));
        }

        //断开连接
        close(conn);
        close(creat_socket);
        return 0;
}


客户端程序:

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

using namespace std;

#define ERR_EXIT(m) \
        do  \
        {   \
            perror(m);  \
            exit(EXIT_FAILURE); \
        } while(0);

int main()
{
        //创建套接字
        int creat_socket;
        creat_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(creat_socket < 0)
        {
                    ERR_EXIT("socket");
        }


        //分配套接字地址
        struct sockaddr_in servaddr;
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET; //表示使用的IPV4
        servaddr.sin_port = htons(3453);
        servaddr.sin_addr.s_addr = inet_addr("192.168.204.131");

        //请求连接
        if (connect(creat_socket, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
        {
                ERR_EXIT("connect");
        }

        // 4. 数据交换
        char recvbuf[1024];
        char sendbuf[1024];
        while (fgets(sendbuf, sizeof sendbuf, stdin) != NULL)   // 键盘输入获取
        {
//               memset(recvbuf, 0, sizeof recvbuf);
//               memset(sendbuf, 0, sizeof sendbuf);
                 write(creat_socket, sendbuf, sizeof sendbuf); // 写入服务器
                 int ret = read(creat_socket, recvbuf, sizeof recvbuf);    // 服务器读取
                 fputs(recvbuf, stdout); // 服务器返回数据输出

        // 清空
                  memset(recvbuf, 0, sizeof recvbuf);
                  memset(sendbuf, 0, sizeof sendbuf);
        }

         // 5. 断开连接
        close(creat_socket);
        return 0;
}

需要在linux下运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值