Linux下socket编程的简单实例

1 服务器端的socket编程

服务器端主要的功能,就是创建socket监听,等待客户端的连接。
基础的步骤很简单,如下:

(1) 创建socket;
(2) 绑定地址和端口;
(3) 启动监听;
(4) 接受客户端请求;
(5) 读/写数据;

1.1 创建socket:

函数原型:

mysocket = socket(int socket_family, int socket_type, int protocol);

第一个参数为socket的协议族,由一组宏定义表示,一般使用AF_INET,表示使用IPV4协议。
第二个参数为socket的类型,主要分为SOCK_STREAMSOCK_DGRAM,分别对应TCP协议和UDP协议。
第三个参数为socket使用的特定协议,一般对应一个协议族就只有一个协议,可以使用0表示使用默认的协议。
函数返回值为创建的socket文件描述符。-1表示创建失败。
函数定义及相关宏定义在头文件<sys/socket.h>

1.2 绑定地址和端口:

函数原型:

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

第一个参数为刚刚创建的socket;
第二个参数是一个结构体sockaddr的指针。但实际使用的时候,根据协议的不同,而使用不同的结构。对于TCP来说,使用sockaddr_in。
第三个参数是第二个参数的结构体的长度。
sockaddr_in的结构为:

struct sockaddr_in
  {
    sa_family_t sin_family;
    in_port_t sin_port;
    struct in_addr sin_addr;

    unsigned char sin_zero[sizeof (struct sockaddr) -
      (sizeof (unsigned short int)) -
      sizeof (in_port_t) -
      sizeof (struct in_addr)];
  };

  //里面的in_addr结构体:
  typedef uint32_t in_addr_t;
  struct in_addr
  {
    in_addr_t s_addr;
  };

1.3 启动监听:

函数原型:

int listen(int sockfd, int backlog);

第一个参数为socket文件描述符;
第二个参数为同时连接数量;

1.4 接受客户端请求:

函数原型:

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

第一个参数为socket文件描述符;
第二个参数为sockaddr结构体指针,用来接收客户端的地址信息。
第三个参数为第二个参数的长度。
返回值为对应的客户端socket的文件描述符,失败则返回-1。
如果没有特殊设置的话,accept会阻塞,直接有连接进来或者出错。

1.5 读/写数据:

有连接进来之后,就可以使用read/write函数进行通讯了。

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

1.6 一个简单的服务器例子:

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

#define PORT 5116
#define BUF_SIZE 256

int main(int argc, char** argv)
{
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1){
        printf("created socket error\n");
        return 0;
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port  = htons(PORT);
    addr.sin_addr.s_addr = INADDR_ANY;//表示使用本机IP

    int len = sizeof(addr);
    if (-1 == bind(fd, (struct sockaddr*)&addr, len)){
        printf("bind socket fail\n");
        close(fd);
        return 0;
    }

    listen(fd, 10);

    int clientFd;
    struct sockaddr_in clientAddr;
    int clientLen = sizeof(clientAddr);
    printf("The server is waiting for connect...\n");                           
    clientFd = accept(fd, (struct sockaddr*)&clientAddr, &clientLen);           

    char szMsg[BUF_SIZE];                                                       
    int n;                                                                      
    if (clientFd > 0){                                                          
        printf("Accept client from %s:%d\n", inet_ntoa(clientAddr.sin_addr), clientAddr.sin_port);                               
        while((n = read(clientFd, szMsg, BUF_SIZE)) > 0){                       
            szMsg[n] = 0;                                                       
            printf("Recv Msg : %s\n", szMsg);                                   
        }                                                                       
        close(clientFd);                                                        
    }                                                                           

    close(fd);                                                                  

    return 0;                                                                   
}       

使用gcc编译,就可以运行,等待客户端的连接了。

2 客户端的socket编程

客户端的功能,就是连接到服务器,然后就可以进行通讯。所以主要的步骤就是填写服务器的地址并进行连接。
(1)创建socket;
(2)连接服务器;
(3)读/写数据;

2.1 连接服务器

创建socket与读/写数据,和服务端的一模一样,这里只讲一下连接这一步。
函数原型:

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

第一个参数为创建的socket文件描述符。
第二个参数为sockaddr结构体指针,服务器端的地址信息。
第三个参数为第二个参数的长度。
可以使用inet_addr将IP地址从字符串形式转换为二进制形式。

2.2 简单的客户端实例:

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

#define PORT 5116
#define BUF_SIZE 256

int main(int argc, char** argv)
{
    int fd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = ntohs(PORT);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    int len = sizeof(addr);

    if (-1 == connect(fd, (struct sockaddr*)&addr, len)){
        printf("Connect to server fail\n");
        return 0;
    }

    char szMsg[BUF_SIZE];
    while(scanf("%s", szMsg)){
        if (!strcmp(szMsg, "quit")){
            break;
        }
        write(fd, szMsg, strlen(szMsg));
    }
    close(fd);
    return 0;
}

3 一些总结

在linux中,一切都是文件,所以socket也和普通文件一样,用文件描述符表示,使用read/write读写,使用close关闭。
对于一般工程而言,服务端会使用epoll之类的来处理多个客户端的连接,保证高效正确的运行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值