TCP 点播和TCP广播的实现

TCP点播代码的实现

客户端1代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

/*
    多个客户端连接同一个服务器
*/
int tcpsock;

//线程的任务函数---》专门接收服务器发送过来的信息
void *recvfromserver(void *arg)
{
    char rbuf[100];
    while(1)
    {
        bzero(rbuf,100);
        recv(tcpsock,rbuf,100,0);
        printf("服务器发送过来的内容是:%s\n",rbuf);
    }
}
int main()
{
    int ret;
    char sbuf[100];
    char otherip[16];
    unsigned short otherport;
    char cmd[500];
    pthread_t id;
    int n;
    
    //定义ipv4地址体变量存放需要绑定的ip和端口号
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=AF_INET;
    bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //自动匹配客户端自己的ip
    bindaddr.sin_port=htons(10000); //客户端的端口号
    
    //定义ipv4地址体变量存放女朋友(服务器)的ip和端口号
    struct sockaddr_in girladdr;
    bzero(&girladdr,sizeof(girladdr));
    girladdr.sin_family=AF_INET;
    girladdr.sin_addr.s_addr=inet_addr("192.168.22.5"); //服务器的ip
    girladdr.sin_port=htons(20000); //服务器的端口号
    
    //创建tcp套接字
    tcpsock=socket(AF_INET,SOCK_STREAM,0);
    if(tcpsock==-1)
    {
        perror("创建tcp套接字失败!\n");
        return -1;
    }
    
    //取消端口绑定的限制
    int on=1;
    setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    
    //绑定客户端自己的ip和端口号
    ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
    if(ret==-1)
    {
        perror("绑定ip端口失败了!\n");
        return -1;
    }
    
    //拨号连接服务器
    ret=connect(tcpsock,(struct sockaddr *)&girladdr,sizeof(girladdr));
    if(ret==-1)
    {
        perror("连接失败了!\n");
        return -1;
    }
    
    //创建一个线程专门接收服务器发送过来的信息
    pthread_create(&id,NULL,recvfromserver,NULL);
    
    //循环从键盘输入内容发送给服务器
    while(1)
    {
        bzero(sbuf,100);
        bzero(otherip,16);
        bzero(cmd,500);
        printf("请输入你的选择,总共四种选择\n");
        printf("1.发送信息给另外一个客户端,拼接格式要求:msg@对方ip@对方端口@你输入的信息!\n");
        printf("2.发送表情包给另外一个客户端,拼接格式要求:emoji@对方ip@对方端口@表情包数据!\n");
        printf("3.发送文件给另外一个客户端,拼接格式要求:file@对方ip@对方端口@文件内容数据!\n");
        printf("4.发送信息给服务器,拼接格式要求:server@真实信息!\n");
        printf("5.发送信息给其他所有的客户端,拼接格式要求:allclient@真实信息!\n");
        printf("6.获取好友列表信息,拼接格式要求:clientlist@我要获取好友信息\n");
        scanf("%d",&n);
        switch(n)
        {
            case 1: //p2p(point to point)发送信息
                printf("请输入对方的ip和端口号!\n");
                scanf("%s",otherip);
                scanf("%hu",&otherport);
                printf("请输入要发送的信息内容!\n");
                //依照制定的通信规则拼接得到完整的数据
                scanf("%s",sbuf);
                sprintf(cmd,"msg@%s@%hu@%s",otherip,otherport,sbuf);
                //发送出去--》给服务器了
                send(tcpsock,cmd,strlen(cmd),0);
                break;
            case 2: //p2p(point to point)发送表情包
                break;
            case 3: //p2p(point to point)发送文件
                break;
            case 4: //发信息给服务器
                break;
        }
        scanf("%s",sbuf);
        //发送给服务器
        write(tcpsock,sbuf,strlen(sbuf));
    }
    
    //关闭套接字
    close(tcpsock);
    return 0;
    
}

客户端2代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

/*
    多个客户端连接同一个服务器
*/
int tcpsock;

//线程的任务函数---》专门接收服务器发送过来的信息
void *recvfromserver(void *arg)
{
    char rbuf[100];
    while(1)
    {
        bzero(rbuf,100);
        recv(tcpsock,rbuf,100,0);
        printf("服务器发送过来的内容是:%s\n",rbuf);
    }
}
int main()
{
    int ret;
    char sbuf[100];
    char otherip[16];
    unsigned short otherport;
    char cmd[500];
    pthread_t id;
    int n;
    
    //定义ipv4地址体变量存放需要绑定的ip和端口号
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=AF_INET;
    bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //自动匹配客户端自己的ip
    bindaddr.sin_port=htons(10001); //客户端的端口号
    
    //定义ipv4地址体变量存放女朋友(服务器)的ip和端口号
    struct sockaddr_in girladdr;
    bzero(&girladdr,sizeof(girladdr));
    girladdr.sin_family=AF_INET;
    girladdr.sin_addr.s_addr=inet_addr("192.168.22.5"); //服务器的ip
    girladdr.sin_port=htons(20000); //服务器的端口号
    
    //创建tcp套接字
    tcpsock=socket(AF_INET,SOCK_STREAM,0);
    if(tcpsock==-1)
    {
        perror("创建tcp套接字失败!\n");
        return -1;
    }
    
    //取消端口绑定的限制
    int on=1;
    setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    
    //绑定客户端自己的ip和端口号
    ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
    if(ret==-1)
    {
        perror("绑定ip端口失败了!\n");
        return -1;
    }
    
    //拨号连接服务器
    ret=connect(tcpsock,(struct sockaddr *)&girladdr,sizeof(girladdr));
    if(ret==-1)
    {
        perror("连接失败了!\n");
        return -1;
    }
    
    //创建一个线程专门接收服务器发送过来的信息
    pthread_create(&id,NULL,recvfromserver,NULL);
    
    //循环从键盘输入内容发送给服务器
    while(1)
    {
        bzero(sbuf,100);
        bzero(otherip,16);
        bzero(cmd,500);
        printf("请输入你的选择,总共四种选择\n");
        printf("1.发送信息给另外一个客户端,拼接格式要求:msg@对方ip@对方端口@你输入的信息!\n");
        printf("2.发送表情包给另外一个客户端,拼接格式要求:emoji@对方ip@对方端口@表情包数据!\n");
        printf("3.发送文件给另外一个客户端,拼接格式要求:file@对方ip@对方端口@文件内容数据!\n");
        printf("4.发送信息给服务器,拼接格式要求:server@真实信息!\n");
        scanf("%d",&n);
        switch(n)
        {
            case 1: //p2p(point to point)发送信息
                printf("请输入对方的ip和端口号!\n");
                scanf("%s",otherip);
                scanf("%hu",&otherport);
                printf("请输入要发送的信息内容!\n");
                //依照制定的通信规则拼接得到完整的数据
                scanf("%s",sbuf);
                sprintf(cmd,"msg@%s@%hu@%s",otherip,otherport,sbuf);
                //发送出去--》给服务器了
                send(tcpsock,cmd,strlen(cmd),0);
                break;
            case 2: //p2p(point to point)发送表情包
                break;
            case 3: //p2p(point to point)发送文件
                break;
            case 4: //发信息给服务器
                break;
        }
        scanf("%s",sbuf);
        //发送给服务器
        write(tcpsock,sbuf,strlen(sbuf));
    }
    
    //关闭套接字
    close(tcpsock);
    return 0;
    
}

客户端3代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

/*
    多个客户端连接同一个服务器
*/
int tcpsock;

//线程的任务函数---》专门接收服务器发送过来的信息
void *recvfromserver(void *arg)
{
    char rbuf[100];
    while(1)
    {
        bzero(rbuf,100);
        recv(tcpsock,rbuf,100,0);
        printf("服务器发送过来的内容是:%s\n",rbuf);
    }
}
int main()
{
    int ret;
    char sbuf[100];
    char otherip[16];
    unsigned short otherport;
    char cmd[500];
    pthread_t id;
    int n;
    
    //定义ipv4地址体变量存放需要绑定的ip和端口号
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=AF_INET;
    bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //自动匹配客户端自己的ip
    bindaddr.sin_port=htons(10002); //客户端的端口号
    
    //定义ipv4地址体变量存放女朋友(服务器)的ip和端口号
    struct sockaddr_in girladdr;
    bzero(&girladdr,sizeof(girladdr));
    girladdr.sin_family=AF_INET;
    girladdr.sin_addr.s_addr=inet_addr("192.168.22.5"); //服务器的ip
    girladdr.sin_port=htons(20000); //服务器的端口号
    
    //创建tcp套接字
    tcpsock=socket(AF_INET,SOCK_STREAM,0);
    if(tcpsock==-1)
    {
        perror("创建tcp套接字失败!\n");
        return -1;
    }
    
    //取消端口绑定的限制
    int on=1;
    setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    
    //绑定客户端自己的ip和端口号
    ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
    if(ret==-1)
    {
        perror("绑定ip端口失败了!\n");
        return -1;
    }
    
    //拨号连接服务器
    ret=connect(tcpsock,(struct sockaddr *)&girladdr,sizeof(girladdr));
    if(ret==-1)
    {
        perror("连接失败了!\n");
        return -1;
    }
    
    //创建一个线程专门接收服务器发送过来的信息
    pthread_create(&id,NULL,recvfromserver,NULL);
    
    //循环从键盘输入内容发送给服务器
    while(1)
    {
        bzero(sbuf,100);
        bzero(otherip,16);
        bzero(cmd,500);
        printf("请输入你的选择,总共四种选择\n");
        printf("1.发送信息给另外一个客户端,拼接格式要求:msg@对方ip@对方端口@你输入的信息!\n");
        printf("2.发送表情包给另外一个客户端,拼接格式要求:emoji@对方ip@对方端口@表情包数据!\n");
        printf("3.发送文件给另外一个客户端,拼接格式要求:file@对方ip@对方端口@文件内容数据!\n");
        printf("4.发送信息给服务器,拼接格式要求:server@真实信息!\n");
        scanf("%d",&n);
        switch(n)
        {
            case 1: //p2p(point to point)发送信息
                printf("请输入对方的ip和端口号!\n");
                scanf("%s",otherip);
                scanf("%hu",&otherport);
                printf("请输入要发送的信息内容!\n");
                //依照制定的通信规则拼接得到完整的数据
                scanf("%s",sbuf);
                sprintf(cmd,"msg@%s@%hu@%s",otherip,otherport,sbuf);
                //发送出去--》给服务器了
                send(tcpsock,cmd,strlen(cmd),0);
                break;
            case 2: //p2p(point to point)发送表情包
                break;
            case 3: //p2p(point to point)发送文件
                break;
            case 4: //发信息给服务器
                break;
        }
        scanf("%s",sbuf);
        //发送给服务器
        write(tcpsock,sbuf,strlen(sbuf));
    }
    
    //关闭套接字
    close(tcpsock);
    return 0;
    
}

服务器代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>


/*
    多个客户端连接同一个服务器
*/

//定义一个结构体表示单链表--》用来存放所有连接成功的客户端信息
struct clientlist
{
    //数据域
    int sock; //套接字文件描述符
    char ip[16]; //存放点分十进制ip
    unsigned short port; //存放端口号
    //指针域
    struct clientlist *next;
};

struct clientlist *myhead;

//封装函数初始化链表的头节点
struct clientlist *list_init()
{
    struct clientlist *head=malloc(sizeof(struct clientlist));
    head->next=NULL;
    return head;
}

//封装函数把节点尾插到链表中
int mylist_add_tail(struct clientlist *newnode,struct clientlist *head)
{
    //定义指针找到链表的尾部
    struct clientlist *p=head;
    while(p->next!=NULL)
        p=p->next;
    
    //尾插新的节点
    p->next=newnode;
    return 0;
}

//线程的任务函数,专门用来广播信息给所有的客户端
void *sendtoallclient(void *arg)
{
    char sbuf[100];
    while(1)
    {
        bzero(sbuf,100);
        printf("请输入要广播给所有客户端的信息!\n");
        scanf("%s",sbuf);
        //广播给所有的客户端--》遍历链表(链表中存储了所有客户端的信息)去发送
        struct clientlist *p=myhead;
        while(p->next!=NULL)
        {
            p=p->next;
            //使用当前p指向的节点中的套接字,把内容逐一发送出去
            send(p->sock,sbuf,strlen(sbuf),0);
        }
    }
}

//线程的任务函数,专门接收各个不同客户端发送过来的信息
void *recvfromclient(void *arg)
{
    char rbuf[500];
    struct clientlist *temp=(struct clientlist *)arg;
    while(1)
    {
        bzero(rbuf,500);
        recv(temp->sock,rbuf,500,0);
    
        //字符串的切割
        char *p=strtok(rbuf,"@");
        if(strcmp(p,"msg")==0)  //说明客户端是想跟另外一个客户端点播发送信息
        {
            //继续切割
            char *p1=strtok(NULL,"@"); //对方ip
            char *p2=strtok(NULL,"@"); //对方端口号
            char *p3=strtok(NULL,"@"); //真实的信息
            //把字符串端口号转换成整数,方便比较
            int portnum=atoi(p2);
            //遍历链表找到目标客户端,然后把信息转发给这个客户端
            struct clientlist *q=myhead;
            while(q->next!=NULL)
            {
                q=q->next;
                //判断当前节点是不是你要找的那个目标客户端
                if(strcmp(q->ip,p1)==0 && q->port==portnum)
                {
                    //发送给目标客户端
                    send(q->sock,p3,strlen(p3),0);
                    break;
                }
            }
        }
        if(strcmp(p,"emoji")==0) //说明客户端是想跟另外一个客户端点播发送表情包
        {
            
        }
        if(strcmp(p,"file")==0)  //说明客户端是想跟另外一个客户端点播发送文件
        {
            
        }
        if(strcmp(p,"server")==0)  //说明客户端是想跟服务器通信
        {
            
        }
        if(strcmp(p,"clientlist")==0)  //说明客户端是想跟服务器把所有的好友信息发给它
        {
            //遍历链表
            //拼接ip和端口号  sprintf  张三ip@张三端口号#李四ip@李四端口号#王五ip@王五端口号
            send( clientlist#拼接好的ip和端口号); 
        }
    }
}


int main()
{
    int tcpsock;
    int ret;
    char rbuf[100];
    pthread_t id;
    pthread_t otherid;
    
    //定义ipv4地址体变量存放需要绑定的ip和端口号
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=AF_INET;
    bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //自动匹配服务器的ip
    bindaddr.sin_port=htons(20000); //女朋友(服务器)的端口号
    
    //定义ipv4地址体变量存放客户端的ip和端口号
    struct sockaddr_in boyaddr;
    int addrsize=sizeof(boyaddr);
    
    //初始化链表的表头
    myhead=list_init();
    
    //创建tcp套接字
    tcpsock=socket(AF_INET,SOCK_STREAM,0);
    if(tcpsock==-1)
    {
        perror("创建tcp套接字失败!\n");
        return -1;
    }
    
    //取消端口绑定的限制
    int on=1;
    setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    
    //绑定女朋友(服务器)自己的ip和端口号
    ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
    if(ret==-1)
    {
        perror("绑定ip端口失败了!\n");
        return -1;
    }
    
    //监听
    ret=listen(tcpsock,5);
    if(ret==-1)
    {
        perror("监听失败!\n");
        return -1;
    }
    printf("旧的套接字(监听套接字)是:%d\n",tcpsock);
    
    //创建一个线程专门用于服务器键盘输入内容,广播给所有的客户端
    pthread_create(&id,NULL,sendtoallclient,NULL);
    
    //循环接受不同客户端的连接请求
    while(1)
    {
        printf("服务器的代码阻塞在accept位置了!\n");
        //接收客户端的连接请求
        ret=accept(tcpsock,(struct sockaddr *)&boyaddr,&addrsize);  
        if(ret==-1)
        {
            perror("接收连接请求失败了!\n");
            return -1;
        }
        
        //创建一个新的节点
        struct clientlist *newnode=malloc(sizeof(struct clientlist));
        //初始化新的节点
        newnode->sock=ret;  //套接字 
        strcpy(newnode->ip,inet_ntoa(boyaddr.sin_addr)); //ip地址
        newnode->port=ntohs(boyaddr.sin_port); //端口号
        
        //尾插刚才的节点
        mylist_add_tail(newnode,myhead);
        
        //顺便创建一个线程专门接收这个客户端发送过来的信息
        pthread_create(&otherid,NULL,recvfromclient,newnode);
    }
    
    
    
    
    //关闭套接字
    close(tcpsock);
    close(ret);
    return 0;
}

TCP 广播代码实现

客户端1代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

/*
    多个客户端连接同一个服务器
*/
int tcpsock;

//线程的任务函数---》专门接收服务器发送过来的信息
void *recvfromserver(void *arg)
{
    char rbuf[100];
    while(1)
    {
        bzero(rbuf,100);
        recv(tcpsock,rbuf,100,0);
        printf("服务器发送过来的内容是:%s\n",rbuf);
    }
}
int main()
{
    int ret;
    char sbuf[100];
    pthread_t id;
    
    //定义ipv4地址体变量存放需要绑定的ip和端口号
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=AF_INET;
    bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //自动匹配客户端自己的ip
    bindaddr.sin_port=htons(10000); //客户端的端口号
    
    //定义ipv4地址体变量存放女朋友(服务器)的ip和端口号
    struct sockaddr_in girladdr;
    bzero(&girladdr,sizeof(girladdr));
    girladdr.sin_family=AF_INET;
    girladdr.sin_addr.s_addr=inet_addr("192.168.22.5"); //服务器的ip
    girladdr.sin_port=htons(20000); //服务器的端口号
    
    //创建tcp套接字
    tcpsock=socket(AF_INET,SOCK_STREAM,0);
    if(tcpsock==-1)
    {
        perror("创建tcp套接字失败!\n");
        return -1;
    }
    
    //取消端口绑定的限制
    int on=1;
    setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    
    //绑定客户端自己的ip和端口号
    ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
    if(ret==-1)
    {
        perror("绑定ip端口失败了!\n");
        return -1;
    }
    
    //拨号连接服务器
    ret=connect(tcpsock,(struct sockaddr *)&girladdr,sizeof(girladdr));
    if(ret==-1)
    {
        perror("连接失败了!\n");
        return -1;
    }
    
    //创建一个线程专门接收服务器发送过来的信息
    pthread_create(&id,NULL,recvfromserver,NULL);
    
    //循环从键盘输入内容发送给服务器
    while(1)
    {
        bzero(sbuf,100);
        printf("请输入要发送给服务器的信息!\n");
        scanf("%s",sbuf);
        //发送给服务器
        write(tcpsock,sbuf,strlen(sbuf));
    }
    
    //关闭套接字
    close(tcpsock);
    return 0;
    
}

客户端2代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

/*
    多个客户端连接同一个服务器
*/
int tcpsock;

//线程的任务函数---》专门接收服务器发送过来的信息
void *recvfromserver(void *arg)
{
    char rbuf[100];
    while(1)
    {
        bzero(rbuf,100);
        recv(tcpsock,rbuf,100,0);
        printf("服务器发送过来的内容是:%s\n",rbuf);
    }
}
int main()
{
    int ret;
    char sbuf[100];
    pthread_t id;
    
    //定义ipv4地址体变量存放需要绑定的ip和端口号
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=AF_INET;
    bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //自动匹配客户端自己的ip
    bindaddr.sin_port=htons(10001); //客户端的端口号
    
    //定义ipv4地址体变量存放女朋友(服务器)的ip和端口号
    struct sockaddr_in girladdr;
    bzero(&girladdr,sizeof(girladdr));
    girladdr.sin_family=AF_INET;
    girladdr.sin_addr.s_addr=inet_addr("192.168.22.5"); //服务器的ip
    girladdr.sin_port=htons(20000); //服务器的端口号
    
    //创建tcp套接字
    tcpsock=socket(AF_INET,SOCK_STREAM,0);
    if(tcpsock==-1)
    {
        perror("创建tcp套接字失败!\n");
        return -1;
    }
    
    //取消端口绑定的限制
    int on=1;
    setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    
    //绑定客户端自己的ip和端口号
    ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
    if(ret==-1)
    {
        perror("绑定ip端口失败了!\n");
        return -1;
    }
    
    //拨号连接服务器
    ret=connect(tcpsock,(struct sockaddr *)&girladdr,sizeof(girladdr));
    if(ret==-1)
    {
        perror("连接失败了!\n");
        return -1;
    }
    
    //创建一个线程专门接收服务器发送过来的信息
    pthread_create(&id,NULL,recvfromserver,NULL);
    
    //循环从键盘输入内容发送给服务器
    while(1)
    {
        bzero(sbuf,100);
        printf("请输入要发送给服务器的信息!\n");
        scanf("%s",sbuf);
        //发送给服务器
        write(tcpsock,sbuf,strlen(sbuf));
    }
    
    //关闭套接字
    close(tcpsock);
    return 0;
    
}

客户端3代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

/*
    多个客户端连接同一个服务器
*/
int tcpsock;

//线程的任务函数---》专门接收服务器发送过来的信息
void *recvfromserver(void *arg)
{
    char rbuf[100];
    while(1)
    {
        bzero(rbuf,100);
        recv(tcpsock,rbuf,100,0);
        printf("服务器发送过来的内容是:%s\n",rbuf);
    }
}
int main()
{
    int ret;
    char sbuf[100];
    pthread_t id;
    
    //定义ipv4地址体变量存放需要绑定的ip和端口号
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=AF_INET;
    bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //自动匹配客户端自己的ip
    bindaddr.sin_port=htons(10002); //客户端的端口号
    
    //定义ipv4地址体变量存放女朋友(服务器)的ip和端口号
    struct sockaddr_in girladdr;
    bzero(&girladdr,sizeof(girladdr));
    girladdr.sin_family=AF_INET;
    girladdr.sin_addr.s_addr=inet_addr("192.168.22.5"); //服务器的ip
    girladdr.sin_port=htons(20000); //服务器的端口号
    
    //创建tcp套接字
    tcpsock=socket(AF_INET,SOCK_STREAM,0);
    if(tcpsock==-1)
    {
        perror("创建tcp套接字失败!\n");
        return -1;
    }
    
    //取消端口绑定的限制
    int on=1;
    setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    
    //绑定客户端自己的ip和端口号
    ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
    if(ret==-1)
    {
        perror("绑定ip端口失败了!\n");
        return -1;
    }
    
    //拨号连接服务器
    ret=connect(tcpsock,(struct sockaddr *)&girladdr,sizeof(girladdr));
    if(ret==-1)
    {
        perror("连接失败了!\n");
        return -1;
    }
    
    //创建一个线程专门接收服务器发送过来的信息
    pthread_create(&id,NULL,recvfromserver,NULL);
    
    //循环从键盘输入内容发送给服务器
    while(1)
    {
        bzero(sbuf,100);
        printf("请输入要发送给服务器的信息!\n");
        scanf("%s",sbuf);
        //发送给服务器
        write(tcpsock,sbuf,strlen(sbuf));
    }
    
    //关闭套接字
    close(tcpsock);
    return 0;
    
}

服务器代码实现

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>


/*
    多个客户端连接同一个服务器
*/

//定义一个结构体表示单链表--》用来存放所有连接成功的客户端信息
struct clientlist
{
    //数据域
    int sock; //套接字文件描述符
    char ip[16]; //存放点分十进制ip
    unsigned short port; //存放端口号
    //指针域
    struct clientlist *next;
};

struct clientlist *myhead;

//封装函数初始化链表的头节点
struct clientlist *list_init()
{
    struct clientlist *head=malloc(sizeof(struct clientlist));
    head->next=NULL;
    return head;
}

//封装函数把节点尾插到链表中
int mylist_add_tail(struct clientlist *newnode,struct clientlist *head)
{
    //定义指针找到链表的尾部
    struct clientlist *p=head;
    while(p->next!=NULL)
        p=p->next;
    
    //尾插新的节点
    p->next=newnode;
    return 0;
}

//线程的任务函数,专门用来广播信息给所有的客户端
void *sendtoallclient(void *arg)
{
    char sbuf[100];
    while(1)
    {
        bzero(sbuf,100);
        printf("请输入要广播给所有客户端的信息!\n");
        scanf("%s",sbuf);
        //广播给所有的客户端--》遍历链表(链表中存储了所有客户端的信息)去发送
        struct clientlist *p=myhead;
        while(p->next!=NULL)
        {
            p=p->next;
            //使用当前p指向的节点中的套接字,把内容逐一发送出去
            send(p->sock,sbuf,strlen(sbuf),0);
        }
    }
}

//线程的任务函数,专门接收各个不同客户端发送过来的信息
void *recvfromclient(void *arg)
{
    char rbuf[100];
    struct clientlist *temp=(struct clientlist *)arg;
    while(1)
    {
        bzero(rbuf,100);
        recv(temp->sock,rbuf,100,0);
        printf("有个客户端,ip:%s  端口:%hu  发送信息给我了,信息是:%s\n",temp->ip,temp->port,rbuf);
    }
}


int main()
{
    int tcpsock;
    int ret;
    char rbuf[100];
    pthread_t id;
    pthread_t otherid;
    
    //定义ipv4地址体变量存放需要绑定的ip和端口号
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=AF_INET;
    bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //自动匹配服务器的ip
    bindaddr.sin_port=htons(20000); //女朋友(服务器)的端口号
    
    //定义ipv4地址体变量存放客户端的ip和端口号
    struct sockaddr_in boyaddr;
    int addrsize=sizeof(boyaddr);
    
    //初始化链表的表头
    myhead=list_init();
    
    //创建tcp套接字
    tcpsock=socket(AF_INET,SOCK_STREAM,0);
    if(tcpsock==-1)
    {
        perror("创建tcp套接字失败!\n");
        return -1;
    }
    
    //取消端口绑定的限制
    int on=1;
    setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    
    //绑定女朋友(服务器)自己的ip和端口号
    ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
    if(ret==-1)
    {
        perror("绑定ip端口失败了!\n");
        return -1;
    }
    
    //监听
    ret=listen(tcpsock,5);
    if(ret==-1)
    {
        perror("监听失败!\n");
        return -1;
    }
    printf("旧的套接字(监听套接字)是:%d\n",tcpsock);
    
    //创建一个线程专门用于服务器键盘输入内容,广播给所有的客户端
    pthread_create(&id,NULL,sendtoallclient,NULL);
    
    //循环接受不同客户端的连接请求
    while(1)
    {
        printf("服务器的代码阻塞在accept位置了!\n");
        //接收客户端的连接请求
        ret=accept(tcpsock,(struct sockaddr *)&boyaddr,&addrsize);  
        if(ret==-1)
        {
            perror("接收连接请求失败了!\n");
            return -1;
        }
        
        //创建一个新的节点
        struct clientlist *newnode=malloc(sizeof(struct clientlist));
        //初始化新的节点
        newnode->sock=ret;  //套接字 
        strcpy(newnode->ip,inet_ntoa(boyaddr.sin_addr)); //ip地址
        newnode->port=ntohs(boyaddr.sin_port); //端口号
        
        //尾插刚才的节点
        mylist_add_tail(newnode,myhead);
        
        //顺便创建一个线程专门接收这个客户端发送过来的信息
        pthread_create(&otherid,NULL,recvfromclient,newnode);
    }
    
    
    
    
    //关闭套接字
    close(tcpsock);
    close(ret);
    return 0;
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肖爱Kun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值