基于TCP的简单通信例程

代码说明:

本程序使用TCP相关函数构建通信,使用pthread文件构建多线程实现同时收发。

一个服务器可连接多个客户端,可接收多个客户端发送的文件信息,但是服务器发送由于键盘输入,所以不确定回复给哪个客户端。

服务器使用8080端口,客户端使用8081端口(可改)

 

相关代码:

//客户端
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <thread>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#include <csignal>

using namespace std;

const int clientcom = 8081;              //设置客户端端口
const int servercom = 8080;              //设置服务器监听端口
const char serverip[] = "192.168.124.3"; //设置服务器IP

bool flag = true; //开关变量

void *threadsend(void *fd);
void *threadrecv(void *fd);

int main()
{
    struct sockaddr_in serveraddr;
    struct sockaddr_in clientaddr;
    socklen_t serverlen = sizeof(serveraddr);
    socklen_t clientlen = sizeof(clientaddr);
    int clientfd; //连接文件描述符
    //填写服务器信息
    memset(&serveraddr, 0, serverlen);
    serveraddr.sin_family = AF_INET;                  //IPV4协议
    serveraddr.sin_port = htons(servercom);           //设置服务器端口
    serveraddr.sin_addr.s_addr = inet_addr(serverip); //服务器IP

    //填写客户端(本机)信息
    memset(&clientaddr, 0, clientlen);
    clientaddr.sin_family = AF_INET;        //IPV4协议
    clientaddr.sin_port = htons(clientcom); //设置端口
    clientaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    //创建文件描述符
    if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        cout << "creat fd fail" << endl;
        return -1;
    }
    //绑定fd与客户端(本机)地址信息
    if ((bind(clientfd, (sockaddr *)&clientaddr, clientlen)) < 0)
    {
        cout << "bind fd fail" << endl;
        return -1;
    }
    //与服务器连接
    if (connect(clientfd, (struct sockaddr *)&serveraddr, serverlen) < 0)
    {
        cout << "connect fail" << endl;
        return -1;
    }
    //连接成功,创建两个线程进行读写操作
    pthread_t t_send;
    pthread_t t_recv;

    pthread_create(&t_send, NULL, threadsend, &clientfd);
    pthread_create(&t_recv, NULL, threadrecv, &clientfd);
    //阻塞,等待返回
    pthread_join(t_send, NULL);
    pthread_join(t_recv, NULL);
    close(clientfd);
    return 0;
}

//写线程
void *threadsend(void *fd)
{
    char sendbuff[100];
    int sendfd = *((int *)fd); //强制转换为int
    while (flag)
    {
        cout << "Input" << endl;
        cin.getline(sendbuff, 100); //等待写入
        if ((send(sendfd, sendbuff, 100, 0)) < 0)
        {
            cout << "send fail" << endl;
        }
    }
    return 0;
}

//读线程
void *threadrecv(void *fd)
{
    int count;
    int recvfd = *((int *)fd); //强制转换为int
    char recvbuff[100];
    while (flag)
    {
        count = 0;
        count = recv(recvfd, recvbuff, 100, 0);
        if (count < 0)
        {
            cout << "recv fail" << endl;
        }
        else if (count > 0)
        {
            recvbuff[count] = 0;  //在接收信息后面加终止符
            cout << "recv :" << recvbuff << endl;
        }
    }
    return 0;
}
//服务端
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <thread>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <pthread.h>

using namespace std;

const int servercom = 8080; //设置服务器监听端口

void *threadcreat(void *fd);
void *threadrecv(void *fd);
void *threadsend(void *fd);

int main()
{
    struct sockaddr_in serveraddr;
    struct sockaddr_in clientaddr;
    socklen_t serverlen = sizeof(serveraddr);
    socklen_t clientlen = sizeof(clientaddr);
    int listenfd;
    vector<int> connectfd(10, -1); //连接符
    int connectnumber = 0;

    //填写服务器信息
    memset(&serveraddr, 0, serverlen);
    serveraddr.sin_family = AF_INET;                //IPV4协议
    serveraddr.sin_port = htons(servercom);         //设置端口
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //设置任意本机IP
    //创建文件描述符
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        cout << "creat fd fail" << endl;
        return -1;
    }
    //绑定fd与地址信息
    if ((bind(listenfd, (sockaddr *)&serveraddr, serverlen)) < 0)
    {
        cout << "bind fd fail" << endl;
        return -1;
    }
    //设置监听队列
    if (listen(listenfd, 1024) < 0)
    {
        cout << "listen fd fail" << endl;
        return -1;
    }
    cout << "server init ok" << endl;
    while (1)
    {
        //每来一个连接请求都会进行一次连接,客户端信息存放在clientaddr中
        if ((connectfd[connectnumber] = accept(listenfd, (struct sockaddr *)&clientaddr, &clientlen)) < 0)
        {
            cout << "connect error!" << endl;
            return -1;
        }
        pthread_t tid; //生成子线程标识符号
        pthread_create(&tid, NULL, threadcreat, &connectfd[connectnumber]);
        connectnumber++;
        cout << "client num:" << connectnumber << endl;
    }
    return 0;
}

//发送线程
void *threadsend(void *fd)
{
    int sendfd = *((int *)fd);
    char temp[100];
    while (1)
    {
        memset(temp, 0, sizeof(temp));
        cout << "Input" << endl;
        cin.getline(temp, 100); //等待写入
        if ((send(sendfd, temp, 100, 0)) < 0)
        {
            cout << "send fail" << endl;
        }
    }
    close(sendfd);
    return 0;
}

//接收线程
void *threadrecv(void *fd)
{
    int recvfd = *((int *)fd);
    int count;
    char temp[100];
    while (1)
    {
        count = 0;
        count = recv(recvfd, temp, 100, 0);
        if (count < 0)
        {
            cout << "recv fail" << endl;
        }
        else if(count>0)
        {
            temp[count] = 0;  //在接收信息后面加终止符
            cout << "recv :" << temp << endl;
        }
    }
    close(recvfd);
    return 0;
}

void *threadcreat(void *fd)
{
    pthread_t t_send, t_recv;
    pthread_create(&t_send, NULL, threadsend, fd);
    pthread_create(&t_recv, NULL, threadrecv, fd);
    return 0;
}

心得:

client客户端编写思路:
1.声明服务器端地址serveraddr 和 客户端服务地址clientaddr
2.填写服务器信息
3.填写客户端自己的信息,主要是绑定端口
4.创建文件描述符fd,fd与本机地址绑定bind,connect函数与服务器连接
5.创建两个线程,一个负责读,一个负责写,传入参数fd
6.主程序中使用join阻塞,线程中使用while(1)一直循环

server服务端编写思路:
1.声明服务器端地址serveraddr 和 客户端服务地址clientaddr
2.填写服务器信息,主要是监听端口信息
3.创建文件描述符fd,fd与服务器绑定bind,设置监听队列
4.主程序进入while(1),使用accept来接收客户端的连接请求,生成的连接文件描述符clientfd存放于数组
5.创建一个新线程t,传入文件描述符clientfd
6.在线程中再次创建两个线程,负责读取和发送,传入clientfd

注意事项:
1.每次发送数据前,使用memset将数组清零
2.每次接收数据后,需要将存储数组后加0以保证显示顺利
3.多线程传入函数形式如下
void *threadrecv(void *fd)
需要将传入参数强制转化为: int recvfd = *((int *)fd);
4.多线程注意头文件的包含,修改CMakeLists文件


多线程pthread使用:
1.头文件中包含#include <pthread.h>;
2.CMakeLists中添加以下命令
find_package(Threads REQUIRED);
target_link_libraries(s1 Threads::Threads)
3.程序中相关命令
pthread_t tid1;    //声明一个线程标识符
pthread_create(&tid1, NULL, threadsend, fd);  //创建一个线程,四个参数分别为线程标识符、线程属性、线程函数、线程参数
pthread_join(tid1,NULL);     //两个参数为被等待的线程标识符、一个用户定义的指针,它可以用来存储被等待线程的返回值。为阻塞函数
pthread_exit(&val);     //在线程中使用,中断线程,唯一的参数是函数的返回代码,传给join中的第二个元素

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很高兴为您提供帮助。下面是一个基于TCP协议的Linux服务器与客户端通信例程: 服务器端: 1. 创建套接字: ``` int server_socket = socket(AF_INET, SOCK_STREAM, 0); ``` 2. 绑定IP地址和端口号: ``` struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); // port为服务器监听的端口号 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)); ``` 3. 监听客户端连接请求: ``` listen(server_socket, 5); // 5为等待连接队列的最大长度 ``` 4. 接受客户端连接请求: ``` struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len); ``` 5. 接收客户端发送的数据: ``` char buffer[1024]; int len = recv(client_socket, buffer, sizeof(buffer), 0); ``` 6. 发送数据给客户端: ``` char* message = "Hello, client!"; send(client_socket, message, strlen(message), 0); ``` 7. 关闭套接字: ``` close(client_socket); close(server_socket); ``` 客户端: 1. 创建套接字: ``` int client_socket = socket(AF_INET, SOCK_STREAM, 0); ``` 2. 连接服务器: ``` struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); // port为服务器监听的端口号 server_addr.sin_addr.s_addr = inet_addr(server_ip); // server_ip为服务器的IP地址 connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)); ``` 3. 发送数据给服务器: ``` char* message = "Hello, server!"; send(client_socket, message, strlen(message), 0); ``` 4. 接收服务器发送的数据: ``` char buffer[1024]; int len = recv(client_socket, buffer, sizeof(buffer), 0); ``` 5. 关闭套接字: ``` close(client_socket); ``` 以上是一个简单的基于TCP协议的Linux服务器与客户端通信例程,希望对您有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值