最近在学习Linux系统编程和网络编程,记录一下学习过程中写过的程序,编程语言为C++,系统为Ubuntu 20.04.2 LTS


1.socket通信

源代码

服务器端源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-21 14:06:19
 * @ Modified Time: 2021-07-21 16:51:53
 * @ Description  : socket通信,实现字符串转换,服务器端代码
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cctype>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>

using namespace std;

const int server_port = 9527;

int main(int argc, char* argv[]){
    printf("-----This is server-----\n");
    int lfd = socket(AF_INET,SOCK_STREAM,0);
    if(lfd == -1){
        perror("socket error");
        exit(1);
    }
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(server_port);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret = bind(lfd,reinterpret_cast<sockaddr*>(&serv_addr),sizeof(serv_addr));
    if(ret == -1){
        perror("bind error");
        exit(1);
    }
    ret = listen(lfd,128);
    if(ret == -1){
        perror("listen error");
        exit(1);
    }
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    int cfd = accept(lfd,reinterpret_cast<struct sockaddr*>(&client_addr),&client_addr_len);
    if(cfd == -1){
        perror("accept error");
        exit(1);
    }
    char client_ip[BUFSIZ];
    printf("client ip = %s, port = %d\n",
        inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_ip,sizeof(client_ip)),
        ntohs(client_addr.sin_port));
    char buf[BUFSIZ];
    int num=0,count = 10;
    while(--count){
        num = read(cfd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,num);
        for(int i=0;i<num;++i){
            buf[i] = toupper(buf[i]);
        }
        write(cfd,buf,num);
    }
    close(lfd);
    close(cfd); 
    printf("-----connection closed-----\n");
    return 0;
}

客户端源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-21 14:53:01
 * @ Modified Time: 2021-07-21 16:55:45
 * @ Description  : socket通信,实现字符串转换,客户端代码
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>

using namespace std;

const int server_port = 9527;

int main(int argc, char* argv[]){
    printf("-----This is client-----\n");
    int cfd = socket(AF_INET,SOCK_STREAM,0);
    if(cfd == -1){
        perror("socket error");
        exit(1);
    }
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);
    int ret = connect(cfd,reinterpret_cast<struct sockaddr*>(&server_addr),sizeof(server_addr));
    if(ret != 0){
        perror("connect error");
        exit(1);
    }
    int count= 10,num = 0;
    char buf[BUFSIZ];
    while(--count){
        write(cfd,"hello\n",6);
        num = read(cfd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,num);
        sleep(1);
    }
    close(cfd);
    printf("-----connection closed-----\n");
    return 0;
}

运行结果

socket.png

2.Socket通信 封装错误处理函数

源代码

封装错误处理 头文件wrap.h

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-22 10:25:18
 * @ Modified Time: 2021-07-22 15:01:15
 * @ Description  : Socket通信 封装错误处理
 */

#ifndef _WRAP_H_
#define _WRAP_H_

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cctype>
#include <cstring>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>

using std::string;

void errorHandle(const string str);
int Socket(int domain, int type, int protocol);
void Bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
void Listen(int sockfd, int backlog);
int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
void Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

#endif

封装错误处理 源文件wrap.cpp

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-22 10:25:28
 * @ Modified Time: 2021-07-22 12:02:07
 * @ Description  : 封装函数,添加错误处理,使代码逻辑更清晰
 */

#include "wrap.h"

void errorHandle(const string str){     //输出错误信息,并退出程序
    perror(str.c_str());
    exit(1);
}
int Socket(int domain, int type, int protocol){
    int lfd = socket(domain,type,protocol);
    if(lfd == -1){
        errorHandle("socket error");
    }
    return lfd;
}
void Bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen){
    int ret = bind(sockfd,addr,addrlen);
    if(ret == -1){
        errorHandle("bind error");
    }
}
void Listen(int sockfd, int backlog){
    int ret = listen(sockfd,backlog);
    if(ret != 0){
        errorHandle("listen error");
    }
}
int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen){
    int cfd = accept(sockfd,addr,addrlen);
    if(cfd == -1){
        errorHandle("accept error");
    }
    return cfd;
}
void Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen){
    int ret = connect(sockfd, addr, addrlen);
    if(ret != 0){
        errorHandle("connect error");
    }
}

服务器端源程序

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-21 14:06:19
 * @ Modified Time: 2021-07-22 14:47:43
 * @ Description  : socket通信,实现字符串转换,服务器端代码
 */

#include "wrap.h"
using namespace std;

const int server_port = 9529;

int main(int argc, char* argv[]){
    printf("-----This is server-----\n");
    int lfd = Socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(server_port);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    Bind(lfd,reinterpret_cast<struct sockaddr*>(&serv_addr),sizeof(serv_addr));
    Listen(lfd,128);
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    int cfd = Accept(lfd, reinterpret_cast<struct sockaddr*>(&client_addr), &client_addr_len);
    char client_ip[BUFSIZ];
    printf("client ip = %s, port = %d\n",
        inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_ip,sizeof(client_ip)),
        ntohs(client_addr.sin_port));
    char buf[BUFSIZ];
    int num=0,count = 10;
    while(--count){
        num = read(cfd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,num);
        for(int i=0;i<num;++i){
            buf[i] = toupper(buf[i]);
        }
        write(cfd,buf,num);
    }
    close(lfd);
    close(cfd); 
    printf("-----connection closed-----\n");
    return 0;
}

客户端源程序

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-21 14:53:01
 * @ Modified Time: 2021-07-22 14:47:49
 * @ Description  : socket通信,实现字符串转换,客户端代码
 */

#include "wrap.h"

using namespace std;

const int server_port = 9529;

int main(int argc, char* argv[]){
    printf("-----This is client-----\n");
    int cfd = Socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);
    Connect(cfd,reinterpret_cast<struct sockaddr*>(&server_addr),sizeof(server_addr)); 
    int count= 10,num = 0;
    char buf[BUFSIZ];
    while(--count){
        write(cfd,"hello\n",6);
        num = read(cfd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,num);
        sleep(1);
    }
    close(cfd);
    printf("-----connection closed-----\n");
    return 0;
}

编译命令

g++ 1.socket_server.cpp wrap.cpp -o server

g++ 1.socket_client.cpp wrap.cpp -o client

运行结果

socket.png

3.多线程Socket通信

源代码

封装错误处理 头文件wrap.h

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-22 10:25:18
 * @ Modified Time: 2021-07-22 15:01:15
 * @ Description  : Socket通信 封装错误处理
 */

#ifndef _WRAP_H_
#define _WRAP_H_

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cctype>
#include <cstring>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>

using std::string;

void errorHandle(const string str);
int Socket(int domain, int type, int protocol);
void Bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
void Listen(int sockfd, int backlog);
int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
void Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

#endif

封装错误处理 源文件wrap.cpp

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-22 10:25:28
 * @ Modified Time: 2021-07-22 12:02:07
 * @ Description  : 封装函数,添加错误处理,使代码逻辑更清晰
 */

#include "wrap.h"

void errorHandle(const string str){     //输出错误信息,并退出程序
    perror(str.c_str());
    exit(1);
}
int Socket(int domain, int type, int protocol){
    int lfd = socket(domain,type,protocol);
    if(lfd == -1){
        errorHandle("socket error");
    }
    return lfd;
}
void Bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen){
    int ret = bind(sockfd,addr,addrlen);
    if(ret == -1){
        errorHandle("bind error");
    }
}
void Listen(int sockfd, int backlog){
    int ret = listen(sockfd,backlog);
    if(ret != 0){
        errorHandle("listen error");
    }
}
int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen){
    int cfd = accept(sockfd,addr,addrlen);
    if(cfd == -1){
        errorHandle("accept error");
    }
    return cfd;
}
void Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen){
    int ret = connect(sockfd, addr, addrlen);
    if(ret != 0){
        errorHandle("connect error");
    }
}

服务器端源程序

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-22 14:15:56
 * @ Modified Time: 2021-07-22 15:09:50
 * @ Description  : 多线程socket通信 服务器端
 */

#include "wrap.h"
#include <strings.h>
#include <pthread.h>

using namespace std;

const int server_port = 9999;   //服务器端口号

struct s_info{
    struct sockaddr_in addr;
    int cfd;
};

void* func(void* arg){
    struct s_info *t = reinterpret_cast<struct s_info*>(arg);
    char buf[BUFSIZ];
    int n, i;
    while(true){
        n = read(t->cfd,buf,BUFSIZ);
        if(n == 0){
            cout<<"----------client "<< t->cfd <<" losed.\n";
            break;
        }
        for(i=0;i<n;++i){
            buf[i] = toupper(buf[i]);   //小写转大写
        }
        write(STDOUT_FILENO,buf,n);     //打印到屏幕
        write(t->cfd,buf,n); 
    }
    close(t->cfd);
    pthread_exit(nullptr);
}

int main(int argc, char* argv[]){
    cout<<"-----This is server.-----\n";
    int lfd = Socket(AF_INET, SOCK_STREAM, 0);
    s_info st[256];
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    Bind(lfd,reinterpret_cast<struct sockaddr*>(&server_addr),sizeof(server_addr));
    Listen(lfd,128);
    int i = 0, cfd;
    char tmp[16];
    pthread_t tid;
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    while(true){
        cfd = Accept(lfd,reinterpret_cast<struct sockaddr*>(&client_addr),&client_addr_len);
        st[i].addr = client_addr;
        st[i].cfd = cfd;
        cout<<"received from "<<inet_ntop(AF_INET,&(st[i]).addr.sin_addr,tmp,sizeof(tmp))
            <<", port : "<<ntohs((st[i]).addr.sin_port)<<"\n";
        pthread_create(&tid,nullptr,func,reinterpret_cast<void*>(&st[i]));
        pthread_detach(tid);
    }
    close(lfd);
    pthread_exit(nullptr);
}

客户端源程序

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-21 14:53:01
 * @ Modified Time: 2021-07-22 15:11:08
 * @ Description  : socket通信,实现字符串转换,客户端代码
 */

#include "wrap.h"

using namespace std;

const int server_port = 9999;

int main(int argc, char* argv[]){
    printf("-----This is client-----\n");
    int cfd = Socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);    //本地 127.0.0.1
    Connect(cfd,reinterpret_cast<struct sockaddr*>(&server_addr),sizeof(server_addr)); 
    int count= 10,num = 0;
    char buf[BUFSIZ];
    string str;
    while(true){
        cin>>str;
        if(str == "quit"){  //输入quit,关闭客户端
            break;
        }
        str+='\n';
        write(cfd,str.c_str(),str.size());
        num = read(cfd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,num);
    }
    close(cfd);
    printf("-----connection closed-----\n");
    return 0;
}

编译命令

g++ 2.multi_socket_server.cpp wrap.cpp -pthread -o server

g++ 2.multi_socket_client.cpp wrap.cpp -o client

运行结果

多线程socket

4.socket通信、端口复用

源代码

错误处理 头文件wrap.h

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-22 10:25:18
 * @ Modified Time: 2021-07-22 15:01:15
 * @ Description  : Socket通信 封装错误处理
 */

#ifndef _WRAP_H_
#define _WRAP_H_

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cctype>
#include <cstring>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>

using std::string;

void errorHandle(const string str);
int Socket(int domain, int type, int protocol);
void Bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
void Listen(int sockfd, int backlog);
int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
void Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

#endif

错误处理源文件wrap.cpp

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-22 10:25:28
 * @ Modified Time: 2021-07-22 12:02:07
 * @ Description  : 封装函数,添加错误处理,使代码逻辑更清晰
 */

#include "wrap.h"

void errorHandle(const string str){     //输出错误信息,并退出程序
    perror(str.c_str());
    exit(1);
}
int Socket(int domain, int type, int protocol){
    int lfd = socket(domain,type,protocol);
    if(lfd == -1){
        errorHandle("socket error");
    }
    return lfd;
}
void Bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen){
    int ret = bind(sockfd,addr,addrlen);
    if(ret == -1){
        errorHandle("bind error");
    }
}
void Listen(int sockfd, int backlog){
    int ret = listen(sockfd,backlog);
    if(ret != 0){
        errorHandle("listen error");
    }
}
int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen){
    int cfd = accept(sockfd,addr,addrlen);
    if(cfd == -1){
        errorHandle("accept error");
    }
    return cfd;
}
void Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen){
    int ret = connect(sockfd, addr, addrlen);
    if(ret != 0){
        errorHandle("connect error");
    }
}

服务器端源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-22 14:15:56
 * @ Modified Time: 2021-07-23 14:29:40
 * @ Description  : 多线程socket通信 服务器端
 */

#include "wrap.h"
#include <strings.h>
#include <pthread.h>

using namespace std;

const int server_port = 9999;   //服务器端口号

struct s_info{
    struct sockaddr_in addr;
    int cfd;
};

void* func(void* arg){
    struct s_info *t = reinterpret_cast<struct s_info*>(arg);
    char buf[BUFSIZ],str[16];
    int n, i;
    while(true){
        n = read(t->cfd,buf,BUFSIZ);
        if(n == 0){
            cout<<"----------client "<< t->cfd <<" losed.\n";
            break;
        }
        for(i=0;i<n;++i){
            buf[i] = toupper(buf[i]);   //小写转大写
        }
        cout<<"received from client " << t->cfd <<", ip: "<<inet_ntop(AF_INET,&t->addr.sin_addr.s_addr,str,sizeof(str))
            <<", port: "<<ntohs(t->addr.sin_port)<<"\n";
        write(STDOUT_FILENO,buf,n);     //打印到屏幕
        write(t->cfd,buf,n); 
    }
    close(t->cfd);
    pthread_exit(nullptr);
}

int main(int argc, char* argv[]){
    cout<<"-----This is server.-----\n";
    int lfd = Socket(AF_INET, SOCK_STREAM, 0);
    int opt = 1;    //设置端口复用
    setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,reinterpret_cast<void*>(&opt),sizeof(opt));
    s_info st[256];
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    Bind(lfd,reinterpret_cast<struct sockaddr*>(&server_addr),sizeof(server_addr));
    Listen(lfd,128);
    int i = 0, cfd;
    char tmp[16];
    pthread_t tid;
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    while(true){
        cfd = Accept(lfd,reinterpret_cast<struct sockaddr*>(&client_addr),&client_addr_len);
        st[i].addr = client_addr;
        st[i].cfd = cfd;
        pthread_create(&tid,nullptr,func,reinterpret_cast<void*>(&st[i]));
        pthread_detach(tid);
        ++i;
    }
    close(lfd);
    pthread_exit(nullptr);
}

客户端源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-21 14:53:01
 * @ Modified Time: 2021-07-23 14:29:43
 * @ Description  : socket通信,实现字符串转换,客户端代码
 */

#include "wrap.h"

using namespace std;

const int server_port = 9999;

int main(int argc, char* argv[]){
    printf("-----This is client-----\n");
    int cfd = Socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);    //本地 127.0.0.1
    Connect(cfd,reinterpret_cast<struct sockaddr*>(&server_addr),sizeof(server_addr)); 
    int count= 10,num = 0;
    char buf[BUFSIZ];
    string str;
    while(true){
        cin>>str;
        if(str == "quit"){  //输入quit,关闭客户端
            break;
        }
        str+='\n';
        write(cfd,str.c_str(),str.size());
        num = read(cfd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,num);
    }
    close(cfd);
    printf("-----connection closed-----\n");
    return 0;
}

运行结果

socket.png

最后修改:2021 年 07 月 23 日 02 : 42 PM