socket通信介绍

一、socket介绍

Socket即套接字,的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原义那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。

所以简单的说,socket就是:IP地址+TCP或UDP端口号。

二、socket相关api

1、创建socket

int socket(int domain,int type,int protocol);

domain:即协议域,又称为协议族(family),决定了socket的地址类型。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称                   AF_UNIX,Unix域socket)、AF_ROUTE等,一般我们使用AF_INET。

type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、                                        SOCK_SEQPACKET等

protocol:指定协议类型,常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。一般使用默认,设置为0

返回值为套接字描述符

2、绑定

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockfd:创建好的socket描述字

addr:指向要绑定给sockfd的协议地址。ipv4和ipv6使用的结构体不同

ipv4:

struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */
    struct in_addr sin_addr;   /* internet address */
};

/* Internet address. */
struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};

ipv6

struct sockaddr_in6 { 
    sa_family_t     sin6_family;   /* AF_INET6 */ 
    in_port_t       sin6_port;     /* port number */ 
    uint32_t        sin6_flowinfo; /* IPv6 flow information */ 
    struct in6_addr sin6_addr;     /* IPv6 address */ 
    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
};

struct in6_addr { 
    unsigned char   s6_addr[16];   /* IPv6 address */ 
};

addrlen:对应的是地址的长度

3、监听

int listen(int sockfd, int backlog);

socked:创建好的socket描述字

backlog:socket可以排队的最大连接个数,一般为5~10

4、请求连接

int accept(int sockfd,struct sockaddr* addr,socklen_t* addrlen);

socked:套接字描述字

addr:用于返回客户端的协议地址

addrlen:协议地址的长度

返回值:成功返回客户端的文件描述符,失败返回-1

5、创建连接

int connect(int sockfd,const struct sockaddr* addr,socklen_t addrlen);

socked:套接字描述字

addr:要结合的地址和端口号,即服务器的socket地址

addrlen:socket地址的长度

6、发送/接收数据

调用网络I/O进行读写操作有一下几组函数。一般使用send/recv

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

sockfd:套接字描述字

buf:发送/接收缓冲区

len:缓冲区长度

flags:调用操作方式,具体组合可点击

返回值为实际写入读出的长度

7,关闭socket

int close(int fd);

int shutdown(int sockfd,int how);

 

三、使用socket

服务端即客户端调用顺序如下图:

四、socket通信代码实例

服务端:

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

#define MAXLINE 4096

int main(int argc, char** argv)
{
    int listenfd, connfd;
    struct sockaddr_in servaddr;
    char buff[4096];
    int n;

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
    {
        printf("create socket error: %s(errno: %d)/n",strerror(errno),errno);
        exit(0);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY表示任何IP
    servaddr.sin_port = htons(6000);  //绑定端口6000

    if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
    {
        printf("bind socket error: %s(errno: %d)/n",strerror(errno),errno);
        exit(0);
    }

    if( listen(listenfd, 10) == -1)
    {
        printf("listen socket error: %s(errno: %d)/n",strerror(errno),errno);
        exit(0);
    }

    printf("======waiting for client's request======/n");

    while(1){
        if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1)
        {
            printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
            continue;
        }

        n = recv(connfd, buff, MAXLINE, 0);
        buff[n] = '/0';
        printf("recv msg from client: %s/n", buff);
        close(connfd);
    }
    close(listenfd);
}

客户端:

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

#define MAXLINE 4096

int main(int argc, char** argv)
{
    int sockfd, n;
    char recvline[4096], sendline[4096];
    struct sockaddr_in servaddr;

    if( argc != 2)
    {
        printf("usage: ./client <ipaddress>/n");
        exit(0);
    }

    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("create socket error: %s(errno: %d)/n", strerror(errno),errno);
        exit(0);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(6000);
    if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
    {
        printf("inet_pton error for %s/n",argv[1]);
        exit(0);
    }

    if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    {
        printf("connect error: %s(errno: %d)/n",strerror(errno),errno);
        exit(0);
    }

    printf("send msg to server: /n");
    fgets(sendline, 4096, stdin);
    if( send(sockfd, sendline, strlen(sendline), 0) < 0)
    {
        printf("send msg error: %s(errno: %d)/n", strerror(errno), errno);
        exit(0);
    }

    close(sockfd);
    exit(0);
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值