Socket实现“回射客户端/服务器”功能

TCP客户/服务器模型

服务器端:

/*
   回射客户/服务器应用程序
   功能:客户端输入字符,发送给服务器,服务器不对该字符串做任何处理,又反回客户端
*/

//服务器端函数
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

int main()
{
    int listenfd;
    int run;
	
	//首先调用socket()函数创建套接字
	/*
		socket()函数
		包含头文件:<sys/socket.h>
		功能:创建一个套接字用于通信
		原型:int socket (int domain , int type, int protocol);
		参数:
		    domain: 指定通信协议族
			type: 指定socket类型,流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW
			protocol: 协议类型
		返回值:成功反回非负数,称为套接字
		        失败返回-1,
				
		
		被动套接字:接受连接accept()
		主动套接字(默认):发起连接 connect()
	*/
    listenfd =socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); //在LINUX 下可以用man socket 查询该函数的具体描述
    if(listenfd < 0)
    {
	printf("ERROR\n");
	return -1;
    }
    struct sockaddr_in servaddr;           //IPV4的地址结构
    memset(&servaddr,0,sizeof(servaddr));  
	// 初始化地址
    servaddr.sin_family = AF_INET;         //地址的家族
    servaddr.sin_port = htons(5188);       //端口号,2个字节,这里需要的是网络字节序(大端),需要将5188转换为网络字节序
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //设置地址,INADDR_ANY表示本地的任意地址
    //servaddr.sin_addr.s_addr =inet_addr("127.0.0.1"); //显示指定地址,inet_addr()将点分式地址转换为10进制
    // inet_aton("127.0.0.1",&servaddr.sin_addr);
	
	//第二步为套接字绑定一个本地地址
	/*
	    bind()
		包含头文件<sys/socket.h>
		功能:绑定一个本地地址到套接字
		原型:int bind(int sockfd ,const struct sockaddr *addr, socklen_t);
		参数: sockfd :socket()函数返回的套接字
		       addr: 要绑定的地址,(接受的为一个通用地址,使用时可能需要强制类型转换)
			   addrlen: 要绑定的地址长度,可以用sizeof()计算
	    返回值:成功返回0,失败返回-1
	*/
    run=bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    if(run  < 0)
    {
	    printf("error\n");
        return -2;
    }
	
	//第三步:使套接字处于监听状态
	/*
	    listen()
		包含头文件;<sys/socket.h>
		功能:使套接字从close状态,设置为监听状态,转换为监听状态才能接受连接
		原型: int listen(int sockfd, int backlog);
		参数:
		    sockfd: socket()函数返回的套接字
			backlog: 设置内核为此套接字排队的最大连接个数
        返回值:成功返回0,失败返回-1	
          
        一般来说,listen函数应该在调用socket和bind函数之后,在调用accept函数之前,将套接字由主动变为被动套接字
        对于给定的监听套接口,内核要维护两个队列:
             1.已由客户发出并送达到服务器,服务器正在等待完成相应的TCP三次握手过程
             2. 已完成连接的队列
          			 
		两个队列之和不超过backlog
	*/
    run = listen(listenfd,SOMAXCONN);
    if(run < 0)
    {
       printf("error\n");
       return -3;
    }
    struct sockaddr_in peeraddr;         //定义对方的地址
    socklen_t peerlen =sizeof(peeraddr); //定义对方的地址长度大小,注意需要有初始值,负责 accept()会失败
    int conn;
	
	//第四步:从已完成连接队列中返回第一个连接,如果没有连接过来一直处于阻塞状态
	/*
		头文件:<sys/socket.h>
		功能: 从已完成连接队列中返回第一个连接,如果已完成队列为空,则阻塞
		原型: int accept(int sockfd , struct sockaddr * addr , socklen_t *addrlen);
		参数: sockfd:服务器套接字
		    addr :返回对等方的套接字地址
		       addrlen:返回对等方的套接字地址长度
		返回值:成功返回非负正数(新得到的套接字,将这个套接字称为已连接套接字),失败返回-1
	*/
    conn = accept(listenfd,(struct sockaddr *)&peeraddr,&peerlen);
    if(conn < 0)
    {
		printf("error\n");
		return  -4;
    }
    char recvbuf[1024];
    //实现回射通信
    while(1)
    {   
        memset(recvbuf,0,sizeof(recvbuf));
		int ret=0;
		//接受客户端的请求
        ret = read(conn,recvbuf,sizeof(recvbuf)); //返回实际接受到的字节数
		//对请求进行处理
		printf("%s",recvbuf);
		//对客户端进行数据应答
        write(conn,recvbuf,ret);
    }
	//关闭套接口
	close(conn);
	close(listenfd);
	
	return 0;
}

客户端:

#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

int main()
{
    int sock;
    int error=0;
	//第一步 创建客户端套接字
    sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(sock < 0)
    {
	printf("error socket();\n");
        return -1;
    }
    //设置连接地址
    struct sockaddr_in client;
    memset(&client,0,sizeof(client));
    client.sin_family=AF_INET;
    client.sin_port=htons(5188);
    client.sin_addr.s_addr =inet_addr("127.0.0.1");
	//客户端发起连接
    error=connect(sock,(struct sockaddr *)&client,sizeof(client));
    if(error<0)
    {
        printf("error connect();%d\n",error);
        return -2;
    }
    char sendbuff[1024];
    char recvbuff[1024];
    while(fgets(sendbuff,sizeof(sendbuff),stdin)!=NULL )
    {   
        //传送数据     
	    write(sock,sendbuff,strlen(sendbuff));
        //读取返回数据
		read(sock,recvbuff,sizeof(recvbuff));
		memset(sendbuff,0,sizeof(sendbuff));
        fputs(recvbuff,stdout);
		memset(recvbuff,0,sizeof(recvbuff)); 
    }
	//关闭套接口
    close(sock);
    return 0;
}



  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值