TCP客户端服务器通信 recv()/send()

本文介绍了如何使用TCP进行客户端服务器通信,重点讲解了send()和recv()函数的使用,并提供了相关代码示例。此外,还通过两个练习深化理解:一是实现客户端从服务器下载文件,二是利用wasd键盘输入控制机械臂的操作。
摘要由CSDN通过智能技术生成

1. send()

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:
发送数据
参数:
sockfd:
文件描述符
服务器:
accept的返回值
客户端:
socket的返回值
buf:
要发送的数据
len:
发送的数据的长度
flags:
标志位
0    阻塞
MSG_DONTWAIT  非阻塞
返回值:
成功:
发送的字节数
失败:
-1

write(fd, buf, N) 
<==>
send(fd, buf, N, 0)
<==>
sendto(fd, buf, N, 0, NULL, 0);

2. recv()

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
接收数据
参数:
sockfd:
文件描述符
服务器:
accept的返回值
客户端:
socket的返回值
buf:
保存接收到的数据
len:
接收的数据的长度
flags:
标志位
0    阻塞
MSG_DONTWAIT  非阻塞     
返回值:
成功:
接收的字节数
失败:
-1
0   当发送端关闭套接字或者结束程序时,接收端会返回0

read(fd, buf, N) 
<==>
recv(fd, buf, N, 0)
<==>
recvfrom(fd, buf, N, 0, NULL, NULL);

3. 相关代码

3.1 服务器

//TCP网络编程之服务器

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

#define N 128

//__FILE__: 获取文件名
//__func__:获取函数名
//__LINE__:获取行号
#define ERRLOG(errmsg) do{\
                            perror(errmsg);\
                            printf("%s-%s-%d\n", __FILE__, __func__, __LINE__);\
                            exit(1);\
                            }while(0)

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
        exit(1);
    }

    int sockfd, acceptfd;
    struct sockaddr_in serveraddr, clientaddr;
    socklen_t addrlen = sizeof(struct sockaddr_in);
    char buf[N] = {0};
    ssize_t bytes;

    //第一步:创建套接字
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        ERRLOG("socket error");
    }

    //第二步:填充服务器网络信息结构体
    //inet_addr:将点分十进制ip地址转化为无符号32位整形数据
    //htons:将主机字节序转化为网络字节序
    //atoi:将数字型字符串转化为整形数据   "1568" --> 1568
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    //第三步:将套接字与服务器网络信息结构体绑定
    if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) == -1)
    {
        ERRLOG("bind error");
    }

    //第四步:将套接字设置为被动监听状态
    if(listen(sockfd, 5) == -1)
    {
        ERRLOG("listen error");
    }

    //第五步:阻塞等到客户端的连接
    if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) == -1)
    {
        ERRLOG("accept error");
    }

    //输出客户端的信息
    printf("[%s - %d]\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

    //进行通信
    while(1)
    {
        if((bytes = recv(acceptfd, buf, N, 0)) == -1)
        {
            ERRLOG("recv error");
        }
        else if(bytes == 0)
        {
            printf("客户端[%s - %d]退出了\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
            exit(0);
        }

        if(strcmp(buf, "quit") == 0)
        {
            printf("客户端[%s - %d]退出了\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
            exit(0);
        }

        printf("客户端[%s - %d]:%s\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), buf);

        strcat(buf, " ^_^");

        //如果接收端退出或者关闭套接字,send函数在第二次执行时
        //会产生SIGPIPE,默认对当前进程的处理方式是结束进程
        if(send(acceptfd, buf, N, 0) == -1)
        {
       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小徐的记事本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值