socket套接字(服务器和客户端编程) linux网络编程

概述

所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口

编程流程

服务器端:
1.socket() 建立套接字
2.bind() 绑定IP端口号 (struct sockaddr_in addr 初始化)
3.listen() 指定同时最大连接数
4.accept() 阻塞等待客服端发起连接
5.read() 读取数据
6.处理数据,大小写转换
7.write() 回写给客户端
8.循环读写
9.close

客户端:
1.socket() 建立套接字
2.bind() 绑定IP端口号 (struct sockaddr_in addr 初始化)(隐式绑定默认调用,客户端可以不写这个函数)
3.connect() 发起连接
4.write() 写数据
5.read() 读取数据
6.循环读写
7.close

struct sockaddr_in addr结构如下
在这里插入图片描述

服务器

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<string.h>

#define SERV_IP "127.0.0.1"
#define SERV_PORT 6666  //端口号
int main()
{
    int lfd,cfd;
    struct sockaddr_in serv_addr;//传入参数,设置属性
    struct sockaddr_in clien_addr;//传出参数,获取客户端属性
    socklen_t clien_addr_len,clien_ip_len; //传出参数
    char buf_ip[BUFSIZ];//缓冲区
    int n,ret;

    lfd=socket(AF_INET,SOCK_STREAM,0);//建立本地套接字
    /*参数1:选择网络IP类型
     * AF_INET:  IPV4标准;
     * AF_INET6: IPV6标准
     * 参数2:选择协议种类
     * SOCK_STREAM:基于字节流的连接,默认TCP连接
     * SOCK_DGRAM: 无连接、固定长度的传输调用,默认UDP连接
     * 参数3:选择默认方式,一般为0,表示参数2使用默认协议。
     */
    if(lfd==-1)
    {
        perror("socket error ");
        exit(1);
    }
    int opt=1;
    setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
	//端口地址复用,当服务器主动关闭时,就算处于wait_time状态(主动关闭一方最后需要等待2MSL时间确保最后一个ACK发送成功,保证完整的4次握手关闭连接),重启后也能马上连接新的客户端

    bzero(&serv_addr,sizeof(serv_addr));    //初始化
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port=htons(SERV_PORT);  //绑定端口,本地字节序转换为网络字节序,兼容各个平台大小端的模式。
    //serv_addr.sin_addr.s_addr=inet_pton(SERV_IP);//本地IP转化为网络字节序
    serv_addr.sin_addr.s_addr=htons(INADDR_ANY);//INADDR_ANY宏自动寻找一个可用的IP

    ret=bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//绑定端口和IP
    /*参数1:套接字描述符
     *参数2:属性设置的结构体,注意要强转(版本遗留问题,原先结构体已废弃)
     *参数3:结构体大小
     */
    if(ret==-1)
    {
        perror("bind error");
        exit(1);
    }

    ret=listen(lfd,128);//允许最大128个客服端同时连接,同时使lfd成为一个监听描述符
    if(ret==-1)
    {
        perror("listen error");
        exit(1);
    }
    clien_addr_len=sizeof(clien_addr);  //设置默认大小
    cfd=accept(lfd,(struct sockaddr *)&clien_addr,&clien_addr_len);
    /*参数1:套接字描述符
     *参数2:传出参数,表示客户端属性 
     *参数3:传入传出参数
     *返回一个新的socket文件描述符,用于与客户端通信
     */
    if(cfd==-1)
    {
        perror("accept error");
        exit(1);
    }
    printf("client IP: %s,client port:%d\n ",
            inet_ntop(AF_INET,&clien_addr.sin_addr.s_addr,buf_ip,sizeof(buf_ip)),
            ntohs(clien_addr.sin_port));
   while(1)
    {
        char buf[BUFSIZ];
        memset(buf,0,sizeof(buf));
        // printf("buf size=%lu ,strlen=%d   ",sizeof(buf),strlen(buf));
        n=read(cfd,buf,sizeof(buf));//读取 
        if(n==0)
            break;
        printf("accept buf %s, length=%d\n",buf,n);
        for(int i=0;i<n;i++)//字符串全部转为大写
            buf[i]=toupper(buf[i]);
        write(cfd,buf,n);//写入
    }
    close(lfd);
    close(cfd);

    return 0;
}

客户端

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<string.h>

#define SERV_IP "127.0.0.1"
#define SERV_PORT  6666
int main()
{
    int cfd,sfd;
    struct sockaddr_in serv_addr;
    socklen_t serv_addr_len;
    char buf[BUFSIZ],clien_ip[BUFSIZ];
    int n;
    char *find;

    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port=htons(SERV_PORT);//转换为网络字节序
    //serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY可以自行寻找ip
    inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);

    cfd=socket(AF_INET,SOCK_STREAM,0);//创建本地套接字

    // bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//绑定

    connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr) );

    while(1)
    {
        fgets(buf,sizeof(buf),stdin);//从输入端读一行数据存入缓存区中
        find=strchr(buf,'\n');
        if(find)
            *find='\0';//去掉fgets中的换行符
        write(cfd,buf,strlen(buf));
        n=read(cfd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,n);
        printf("\n");
    }   
    close(cfd);
    return 0;
}

结果如下:成功实现通信和返回处理

在这里插入图片描述

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值