socket通信----C语言

服务器端

// 流程: socket()-->bind()-->listen()-->accept() {send(); recv()}
  • socket():使用系统调用 socket()来获得文件描述符
// int socket(int domain, int type, int protocol) ,在头文件<sys/socket.h>
int socketStatus = socket(AF_INET,SOCK_STREAM,0);  //通信类型,最常用的值是 "AF_INET"
                                                //套接口的类型:SOCK_STREAM 或SOCK_DGRAM
                                                //0
                                                // 返回一个套接口描述符,如果出错,则返回-1
  • bind():把套接口绑定到本地计算机的某一个端口。不绑定,则会随机选择一个端口
//int bindStatus = bind(int sockfd, struct sockaddr* my_addr, int addrlen); 
//结构体 struct sockaddr 和 struct sockaddr_in
//一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数x
struct sockaddr
  {
    __SOCKADDR_COMMON (sa_);    //unsigned short sa_family;
                                /* Common data: address family and length.  协议族*/
    char sa_data[14];       /* Address data.  地址+端口号*/
  };

//在头文件<netinet/in.h> 地址和端口号分离
/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);           /* 协议族 */ //unsigned short sa_family;
    in_port_t sin_port;         /* Port number. 端口号 */ //unsigned short int sin_port; 
    struct in_addr sin_addr;        /* Internet address. IP地址 */

    /* Pad to size of `struct sockaddr'.  用于填充的0字节 */ //unsigned char sin_zero[8];
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
  };

/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };

构建地址结构体:

struct sockaddr_in mysock;

bzero(&mysock,sizeof(mysock));  //初始化结构体,填充0个0,使得2个结构体大小相等
mysock.sin_family = AF_INET;  //设置地址家族
mysock.sin_port = htons(800);  //设置端口 htons()    "Host to Network Short"
                                //计算机数据表示存在两种字节顺序:NBO与HBO
                                //网络字节顺序NBO(Network Byte Order)
                                //主机字节顺序(HBO,Host Byte Order)
mysock.sin_addr.s_addr = inet_addr("192.168.1.0");  //设置地址
                    //将字符串点数格式地址转化成无符号长整型(unsigned long s_addr s_addr;)

bind():

int bindStatus = bind(socketStatus,(struct sockaddr *)&mysock,sizeof(struct sockaddr);  /* bind的时候进行转化 */
  • listen():希望等待一个进入的连接请求,然后再处理它们
//int listen(int sockfd, int backlog);  //第一个参数是系统调用 socket()返回的套接口文件描述符。
                                        //第二个参数是进入队列中允许的连接的个数。

int listenStatus = listen(socketStatus, 5);
  • accept():在远程的主机可能试图使用 connect()连接你使用listen()正在监听的端口。但此连接将会在队列中等待,直到使用 accept()处理它。调用 accept()之后,将会返回一个全新的套接口文件描述符来处理这个单个的连接。这样,对于同一个连接来说,你就有了两个文件描述符。原先的一个文件描述符正在监听你指定的端口,新的文件描述符可以用来调用 send()和 recv()。
//int accept(int sockfd, void *addr, unsigned int *addrlen); //第一个参数是正在监听端口的套接口文件描述符。
                                //第二个参数 addr 是指向本地的数据结构sockaddr_in 的指针。通过它你可以了解哪个主机在哪个端口呼叫你。
                                //第三个参数同样可以使用 sizeof(struct sockaddr_in)来获得
unsigned int *sin_size=sizeof(struct sockaddr_in);
struct sockaddr_in Client_addr;
int newSocketStatus = accept(socketStatus, &Client_addr, &sin_size);
  • send()recv():信息发送和接受。正确返回数据长度,错误返回 -1
// int send(int sockfd, const void* msg, int len, int flags);  
//第一个参数是你希望给发送数据的套接口文件描述符。
//它可以是你通过 socket()系统调用返回的,也可以是通过 accept()系统调用得到的。
//第二个参数是指向你希望发送的数据的指针。第三个参数是数据的字节长度。第四个参数标志设置为 0。

//int recv(int sockfd, void* buf, int len, unsigned int flags);  
//第一个参数是要读取的套接口文件描述符.第二个参数是保存读入信息的地址。第三个参数是缓冲区的最大长度。第四个参数设置为 0

客户端

多一个主动的connect()

int connect(int sockfd, struct sockaddr * serv_addr, int addrlen);  
//第一个参数还是套接口文件描述符,它是由系统调用 socket()返回的。第二个参数是 serv_addr 是指向数据结构 sockaddr 的指针,
//其中包括目的端口和 IP 地址。第三个参数可以使用 sizeof(struct sockaddr)而获得。

代码

server.c

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

int main()
{
    int sfp,nfp;
    struct sockaddr_in s_add,c_add;
    unsigned int sin_size;
    unsigned short portnum=2333;     //port number
    sfp = socket(AF_INET, SOCK_STREAM, 0);

    if(-1 == sfp)
    {
        printf("socket fail ! \r\n");
        return -1;
    }
    printf("socket ok !\r\n");


    s_add.sin_family=AF_INET;
    s_add.sin_addr.s_addr=htonl(INADDR_ANY);
    s_add.sin_port=htons(portnum);
    bzero(&(s_add.sin_zero), 8);

    if(-1 == bind(sfp,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
    {
        printf("bind fail !\r\n");
        return -1;
    }

    if(-1 == listen(sfp,5))
    {
        printf("listen fail !\r\n");
        return -1;
    }

    while(1)
    {
        sin_size = sizeof(struct sockaddr_in);
        nfp = accept(sfp, (struct sockaddr *)(&c_add), &sin_size);
        if(-1 == nfp)
        {
            printf("accept fail !\r\n");
            return -1;
        }
        printf("waiting for %#x : %#x\r\n",ntohl(c_add.sin_addr.s_addr),ntohs(c_add.sin_port));
        if(-1 == send(nfp,"hello,socket\r\n", 14, 0))
        {
            printf("write fail!\r\n");
            return -1;
        }
        printf("write ok!\r\n");
        shutdown(nfp, 2);
    }
    shutdown(sfp, 2);
    return 0;
}

client.c

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

int main()
{
    int cfd;
    int recbytes;
    int sin_size;
    char buffer[1024]={0};   
    struct sockaddr_in s_add,c_add;
    unsigned short portnum=2333;  //port number

    cfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == cfd)
    {
        printf("socket fail ! \r\n");
        return -1;
    }

    bzero(&s_add,sizeof(struct sockaddr_in));
    s_add.sin_family=AF_INET;
    s_add.sin_addr.s_addr= inet_addr("192.168.0.13");   //IP of your PC 
    s_add.sin_port=htons(portnum);
    printf("server_addr = %#x : %#x\r\n",ntohl(s_add.sin_addr.s_addr),ntohs(s_add.sin_port));

    if(-1 == connect(cfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
    {
        printf("connect fail !\r\n");
        return -1;
    }
    printf("connect ok !\r\n");

    if(-1 == (recbytes = recv(cfd,buffer,1024, 0)))
    {
        printf("read data fail !\r\n");
        return -1;
    }
    buffer[recbytes]='\0';
    printf("%s\r\n",buffer);
    //getchar();
    shutdown(cfd, 2);
    return 0;
}

参考

socket编程为什么需要htons(), ntohl(), ntohs(),htons() 函数
[转]socket编程——sockaddr_in结构体操作
sockaddr和sockaddr_in的区别

猜你喜欢

转载自blog.csdn.net/qq_28038207/article/details/81056332