socket编程初步

本文介绍了套接字(socket)的基本概念,它是网络通信中的关键抽象,用于数据交换。详细讲解了网络通信流程,包括客户端和服务端的角色。还展示了创建、连接、绑定、监听和接受等函数的使用,并提供了C++实现的示例代码,帮助读者理解套接字在实际应用中的工作原理。
摘要由CSDN通过智能技术生成

socket介绍

socket,又叫做套接字,是对通讯双方中端点的抽象。在unix中,本着“一切皆文件”的原则,所以我们可以认为socket是一个为了完成当前任务而所创建的一个特殊文件,而网络通讯之间都通过这个socket来完成达到发送/接受数据的目的。


网络通讯流程

在这里插入图片描述

  • 首先,服务端要先创建一个socket,称为监听套接字,然后对所需要进行监听的ip和端口进行绑定(ip可以理解为地址,端口是人名,因为服务端可以一个ip对应多个不同端口),然后开始进行监听客户端的请求,进入accpet阻塞
  • 客户端创建一个套接字,通过套接字绑定所要访问的服务端的ip和端口,然后进行尝试进行connect连接,然后服务端的accpet阻塞就收到了来自客户端的请求,accpet返回的结果是一个新的套接字,称为连接套接字
  • 此时已经建立好了客户端和服务端之间的通讯,两者通过连接套接字来进行数据的接受与发送

函数原型

socket

创建套接字,指定期望的通讯协议类型

#include<sys/socket.h>
int socket(int family,int type,int protocl);

family
指定协议族
AF_INET:IPv4
AF_INET6:IPv6协议

type
套接字类型
SOCK_STREAM:字节流套接字
SOCK_DGRAM:数据报套接字
SOCK_SEQPACKET:有序分组套接字
SOCK_RAW:原始套接字

protocol
某个协议类型常值或者为0

返回值
把套接字看为一个特殊文件,那么其实返回的就是一个套接字的文件描述符(整型),0、1、2分别为标准输入、标准输出、标准错误的文件描述符,所以成功创建的话返回值会大于2,返回-1说明出错


connect

客户端通过connect函数建立与服务端的连接

#include<sys/socket.h>
int connect(int sockfd,const struct sockaddr * servaddr,socklen_t addrlen)

sockfd
这个就是socket()函数返回的文件描述符

sockaddr
指向套接字地址结构的指针

addrlen
sockaddr指针指向的套接字结构的大小

返回值
成功的话返回0,出错返回-1

bind

服务端把一个本地协议地址赋予一个套接字

#include<sys/socket.h>
int bind(int sockfd,const struct sockaddr * myaddr,socklen_t addrlen)

sockfd
这个就是socket()函数返回的文件描述符

myaddr
指向套接字地址结构的指针

addrlen
myaddr指针指向的套接字结构的大小

返回值
成功的话返回0,出错返回-1

listen

服务器调用,
(1)其实通过socket()函数创建的套接字,会被假设为一个主动套接字,即默认这个套接字是后面要用connect()函数发起连接的客户端套接字,而listen就是将这个主动套接字转换为一个被动套接字,即告诉内核应该接受指向这个套接字的连接请求
(2)第二个参数规定了内核应该为相应套接字排队的最大连接个数

#include<sys/socket.h>
int listen(int sockfd,int backlog)

sockfd
这个就是socket()函数返回的文件描述符

backlog
内核应该为相应套接字排队的最大连接个数

返回值
0为成功,-1为失败


accept

服务端通过accept接收listen中监听到的来自客户端的请求

#include<sys/socket.h>
#include<arpa/inet.h>
int accpet(int sockfd,struct sockaddr * cliaddr,socklen_t *addrlen)

sockfd
这个就是socket()函数返回的文件描述符

cliaddr
指向对端进程(客户端)套接字地址结构的指针

addrlen
myaddr指针指向对端进程(客户端)的套接字结构的大小

返回值
成功的话,返回的是一个全新的套接字文件描述符,表示服务端与客户端之间的连接,失败返回-1.这个返回值称为连接套接字,socket()函数的返回值称为监听套接字

示例代码

下面代码简单实现了客户端和服务端的通讯,客户端发送消息给服务端,服务端收到消息后输出,然后发送给客户端…

服务端

#include<stdio.h>
#include<string.h>
#include<stdlib.h>// exit
#include<unistd.h> // read write close
#include<sys/socket.h>
#include<arpa/inet.h>// sockaddr_in
char buff[55];
int main(){
    //1.创建socket,返回监听套接字
    int listen_fd=socket(AF_INET,SOCK_STREAM,0);
    if(listen_fd==-1){
        printf("socket error\n");
        exit(0);
    }
    printf("1.服务端创建套接字成功\n");
    //2.将服务端的通信类型,通信的ip和端口绑定到监听套接字上
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof (server_addr));//清空
    server_addr.sin_family=AF_INET;//协议IPV4
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);//任意IP
    server_addr.sin_port=htons(5010);//端口为5010

    if(bind(listen_fd,(struct sockaddr *)&server_addr,sizeof (server_addr))==-1){
        printf("bind error\n");
        close(listen_fd);
        exit(0);
    }
    printf("2.服务端绑定套接字成功\n");
    //3.对套接字进行监听
    if(listen(listen_fd,20)!=0){
        printf("listen error\n");
        close(listen_fd);
        exit(0);
    }
    printf("3.服务端监听套接字成功\n");
    struct sockaddr_in client_addr;
    socklen_t socklen=sizeof(sockaddr_in);

    //4.accpet阻塞 得到连接套接字
    int connect_fd=accept(listen_fd,(struct sockaddr *)&client_addr,&socklen);
    if(connect_fd==-1){
        printf("accept error\n");
        close(listen_fd);
        exit(0);
    }
    printf("4.服务端收到来自客户端的连接请求!!!!!!!!!!!!!!!!!!!\n");
    while(1){
        memset(buff,0,sizeof (buff));
        int n=read(connect_fd,buff,50);
        if(n<0){
            printf("read error\n");
            close(listen_fd);
            close(connect_fd);
            exit(0);
        }
        printf("服务端收到了来自客户端的信息:\n%s\n",buff);
        printf("下面请输入要发送给客户端的消息\n");
        memset(buff,0,sizeof (buff));
        scanf("%s",buff);
        n=write(connect_fd,buff,strlen(buff));
        if(n<0){
            printf("write error\n");
            close(listen_fd);
            close(connect_fd);
            exit(0);
        }
        printf("服务端消息成功发送\n");
    }
    close(connect_fd);
    close(listen_fd);
    return 0;
}

客户端

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
char buff[55];
int main(){
    //1 创建套接字
    int sock_fd=socket(AF_INET,SOCK_STREAM,0);
    if(sock_fd==-1){
        printf("socket error\n");
        exit(0);
    }
    printf("1.客户端创建套接字成功\n");
    struct sockaddr_in clinent_addr;
    bzero(&clinent_addr,sizeof (clinent_addr));// 清空
    clinent_addr.sin_family=AF_INET;// 协议
    clinent_addr.sin_addr.s_addr=htonl(INADDR_ANY); // ip
    clinent_addr.sin_port=htons(5010);// 端口
    if(connect(sock_fd, (struct sockaddr *)&clinent_addr, sizeof(clinent_addr)) != 0) // 向服务端发起连接清求。
    {   printf("connect error\n");
        close(sock_fd);
        return -1;
    }
    printf("2.客户端连接到服务端成功!!!!!!!!!!!!!!!!\n");
    for(;;){
        printf("下面请输入要发送给服务端的消息\n");
        memset(buff,0,sizeof (buff));
        scanf("%s",buff);
        int n=write(sock_fd,buff,strlen(buff));
        if(n<0){
            printf("write error\n");
            
            exit(0);
        }
        printf("客户端消息成功发送\n");
        memset(buff,0,sizeof (buff));
        n=read(sock_fd,buff,50);
        if(n<0){
            printf("read error\n");
            close(sock_fd);
            exit(0);
        }
        printf("收到了来自服务端的信息:\n%s\n",buff);
        
    }
    close(sock_fd);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我不会c语言

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

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

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

打赏作者

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

抵扣说明:

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

余额充值