Linux下Socket网络编程

简介

在进行socket网络编程之前,我们需要知道socket是什么?在Unix/linux操作系统中有一个哲学思想,那就是万物皆文件,socket也不例外,它是可读、可写、可控制、可关闭的文件描述符。使用socket网络编程实现服务端和客户端之间的通信步骤可由下图结构所示:
在这里插入图片描述

服务端和客户端

1.创建socket

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

domain:系统使用的底层协议族。PF_INET(用于IPv4),PF_INET6(用于IPv6),PF_UNIX(用于UNIX);

type:指定服务类型。SOCK_STREAM(流服务,表示传输层使用TCP),SOCK_UGRAM(数据报,表示传输层使用UDP);

protocol:前两个参数构成的协议集合下,再选择一个具体的协议,一般都设置为0;

2.绑定socket

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

将my_addr所指的socket地址分配给未命名的sockfd文件描述符,addrlen指出该socket地址的长度 成功时返回1,失败返回-1并设置errno;

3.监听socket

int listen(int sockfd, int backlog);

sockfd指被监听的socket,backlog提示内核监听队列的最大长度 成功时返回0,失败返回-1并设置errno;

4.接受连接

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

sockfd是执行过listen系统调用的监听socket,addr是用来获取被接受连接的远端socket地址,该地址的长度由addrlen参数指出

成功时返回一个新的连接socket,该socket唯一地标识了被接受的这个连接,失败时返回-1并设置errno;

5.发起连接

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

sockfd由socket 系统调用返回一个socket。serv_addr是服务器监听的socket地址,addrlen则指定这个地址的长度 成功时放回0;一旦成功,sockfd就唯一地标识了这个连接,客户端就可以通过读写sockfd来与服务器通信。失败放回-1并设置errno;

6.通信
TCP数据读写

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

recv读取sockfd上的数据,buf和len分别指定读缓冲区的位置和大小,flags通常为0。成功时返回实际读取到的数据长度,它可能小于期望的长度,因此需要多次调用recv;出错时返回-1并设置errno;

send往sockfd上写入数据,buf和len分别指定写缓冲区的位置和大小。成功时返回实际写入的数据长度,失败则返回-1并设置errno;

7.关闭连接

int close(int fd);

fd是待关闭的socket;

 

服务端参考代码

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

using namespace std;

int main(int argc, char* argv[])
{
    if(argc < 3)
    {
        printf(" Usage: %s <ip of server> <port of server>\n", argv[0]);
        return -1;
    }

    const char* ip = argv[1];
    int port = atoi(argv[2]);

    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        printf("创建SOCKET失败\n");
        return -1;
    }
    printf("创建SOCKET成功!\n");

    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
   // inet_pton(AF_INET, ip, &serv_addr.sin_addr);
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = htons(INADDR_ANY);
    //serv_addr.sin_port = htons(12345);
    //serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");


    if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("绑定失败!\n");
        return -1;
    }
    printf("绑定成功!\n");

    if(listen(sockfd, 10) < 0)
    {
        printf("监听失败!\n");
        return -1;
    }
    printf("监听成功!\n");

    struct sockaddr_in client_addr;
    socklen_t client_addrlength = sizeof(client_addr);

    int client;
    client = accept(sockfd, (struct sockaddr*)&client_addr, &client_addrlength);
    if(client < 0)
    {
        printf("接受失败!\n");
        return -1;
    }
    char remote[INET_ADDRSTRLEN];
   // printf("%s连接成功!\n", inet_ntop(AF_INET, &client_addr.sin_addr, remote, INET_ADDRSTRLEN));
    printf("有客户端连接进来了:%s\n", inet_ntoa(client_addr.sin_addr));

    char recvBuff[255];

    while(1)
    {
        bzero(recvBuff, sizeof(recvBuff));
        int n = recv(client, recvBuff, sizeof(recvBuff)-1, NULL);
        if(n > 0)
        {
            //recvBuff[n] = '\0';
            printf("接收到%d字节\n", n);
            printf(">> %s\n", recvBuff);
        }
    }

    while(1);

    return 0;
}

客户端参考代码

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

using namespace std;

int main(int argc, char* argv[])
{
    if(argc < 3)
    {
        printf(" Usage: %s <ip of server> <port of server>\n", argv[0]);
        return -1;
    }

    const char* ip = argv[1];
    int port = atoi(argv[2]);

    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        printf("创建SOCKET失败\n");
        return -1;
    }
    printf("创建SOCKET成功!\n");

    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    //inet_pton(AF_INET, ip, &serv_addr.sin_addr);
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = htons(INADDR_ANY);

    //serv_addr.sin_port = htons(12345);
    //serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)))
    {
        printf("连接失败!\n");
        return -1;
    }
    printf("连接成功!\n");

    int r;
    char sendBuff[255];
    while (1)
        {
            memset(sendBuff, 0, 255);
            printf("你要发啥:");
            //scanf("%s", sendBuff);
            gets(sendBuff);
            r = send(sockfd, sendBuff, strlen(sendBuff), NULL);
            if (r > 0)
            {
                    printf(">> 发送%d字节到服务器成功\n", r);
            }
        }

    return 0;
}

对代码进行编译

g++ server.cpp -o server
g++ client.cpp -o client

然后运行

总结

  1. socket->bind->listen->accept->connect->read->write->close构成一个TCP服务端
  2. socket->connect->read->write->close构成一个TCP客户端

查找结构体方法 

在这里插入图片描述

-nir中 n表示显示行号,i表示不区分大小写,r表示逐行扫描

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值