C语言——socket通信详解

关键函数

1、int socket(int family,int type,int protocol)

family:
    指定使用的协议簇:AF_INET(IPv4) AF_INET6(IPv6) AF_LOCAL(UNIX协议) AF_ROUTE(路由套接字) AF_KEY(秘钥套接字)
type:
    指定使用的套接字的类型:SOCK_STREAM(字节流套接字) SOCK_DGRAM
protocol:
    如果套接字类型不是原始套接字,那么这个参数就为0
return:
    如果返回值>0 ,标示 Socket 创建成功!

2、int bind(int sockfd, struct sockaddr *myaddr, int addrlen)

sockfd:
    socket函数返回的套接字描述符 
myaddr:
    是指向本地IP地址的结构体指针 
myaddrlen:
    结构长度 
struct sockaddr{
    
    
	unsigned short sa_family; //通信协议类型族AF_xx
	char sa_data[14];  //14字节协议地址,包含该socket的IP地址和端口号 
}; 
struct sockaddr_in{
    
    
	short int sin_family; //通信协议类型族
	unsigned short int sin_port; //端口号
	struct in_addr sin_addr; //IP地址
	unsigned char si_zero[8];  //填充0以保持与sockaddr结构的长度相同 
};

3、int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addrlen)

sockfd:
    socket函数返回套接字描述符
serv_addr:
    服务器IP地址结构指针
addrlen:
    结构体指针的长度
return:
    成功返回0,失败返回-1

4、int listen(int sockfd, int backlog)

sockfd:
    socket函数绑定bind后套接字描述符
backlog:
    设置可连接客户端的最大连接个数,当有多个客户端向服务器请求时,收到此值的影响。
    默认值20

5、int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen)

sockfd:
    socket函数经过listen后套接字描述符
cliaddr:
    客户端套接字接口地址结构
addrlen:
    客户端地址结构长度

6、int send(int sockfd, const void *msg,int len,int flags)

7、int recv(int sockfd, void *buf,int len,unsigned int flags)

sockfd:
    socket函数的套接字描述符
msg:
    发送数据的指针
buf:
    存放接收数据的缓冲区
len:
    数据的长度,把flags设置为0
return:
    >0表示成功,返回实际发送或接受的字节数;
    =0表示超时,对方主动关闭了连接过程;
    <0出错,此种情况可能出现过重情况,
    其中errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN这三种是特殊情况,
    实际使用中表示继续正常接受数据即可。

服务端

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

int main(int argc, char *argv[])
{
    
    
    int fd, new_fd, struct_len, numbytes,i;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    char buff[BUFSIZ];

    server_addr.sin_family = AF_INET;
    /**
     * 设置服务器Socket 的端口号;
     * 端口号的最大值 65535;  09~1024 是系统默认占用的端口号!不要设置!
     * 如果需要手动设置端口号: 一般设置 1024 ~ 65535 之间的值!
     **/
    server_addr.sin_port = htons(8000);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(server_addr.sin_zero), 8);
    struct_len = sizeof(struct sockaddr_in);

    fd = socket(AF_INET, SOCK_STREAM, 0);
    // 进行连接确认
    while(bind(fd, (struct sockaddr *)&server_addr, struct_len) == -1);
    printf("Bind Success!\n");
    while(listen(fd, 10) == -1);
    printf("Listening....\n");
    printf("Ready for Accept,Waitting...\n");

    new_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len);
    printf("accept return: %d\n", new_fd);
    printf("Get the Client~\n");
    numbytes = send(new_fd,"Welcome to my server\n",21,0);
    while((numbytes = recv(new_fd, buff, BUFSIZ, 0)) > 0)
    {
    
    
        buff[numbytes] = '\0';
        printf("%s\n",buff);
            if(send(new_fd,buff,numbytes,0)<0)
            {
    
    
                perror("write");
                return 1;
            }
    }
    close(new_fd);
    close(fd);
    return 0;
}

客户端

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

int main(int argc,char *argv[])
{
    
    
    int sockfd,numbytes;
    char buf[BUFSIZ];
    struct sockaddr_in their_addr;
    printf("break!");
    //如果得到返回值不为0,说明socket没创建成功,继续等待,与服务端无关
    while((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1);
    printf("We get the sockfd~\n");
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(8000);
    // 服务器 Socket 的 IP 地址
    their_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
    bzero(&(their_addr.sin_zero), 8);
    
    while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1);
    // 当上面建立连接成功后,即connect()返回0,再调用connect()函数,返回就变成-1了
    printf("connect return: %d\n", connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)));
    printf("Get the Server~\n");

    numbytes = recv(sockfd, buf, BUFSIZ,0);//接收服务器端信息 
    // 在接收到的字符串末尾添加一个0,表示终结,避免乱码
    buf[numbytes]='\0';  
    printf("buf: %s\n",buf);
    while(1)
    {
    
    
        printf("Entersome thing:");
        scanf("%[^\n]%*c",buf);
        printf("scanf: %s\n", buf);
        numbytes = send(sockfd, buf, strlen(buf), 0);
        printf("send numbytes: %d\n", numbytes);
        numbytes=recv(sockfd,buf,BUFSIZ,0);  
        printf("recv numbytes: %d\n", numbytes);
        buf[numbytes]='\0'; 
        printf("received:%s\n",buf);  
    }
    close(sockfd);
    return 0;
}

效果展示

先启动服务端,再启动客户端

客户端

在这里插入图片描述

扫描二维码关注公众号,回复: 12716259 查看本文章

服务端

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/WU2629409421perfect/article/details/114448461
今日推荐