首页 > 其他 > 详细

socket编程 --pthread(TCP/IP)

时间:2020-09-28 13:02:34      阅读:33      评论:0      收藏:0      [点我收藏+]
知识点
socket是一种编程接口
socket是一中特殊文件描述符

技术分享图片技术分享图片

技术分享图片

五要素
协议(接头暗号)
本地地址
本地端口
远程地址
远程端口
TCP 三次握手四次挥手

技术分享图片

技术分享图片

技术分享图片

接口转换操作

  1. 字节序转换

技术分享图片
点分十进制数串转网络字节序长整形

int inet_aton(const char *string, struct in_addr*addr)

技术分享图片
2.IP地址转换操作
技术分享图片
结构体
技术分享图片

  • 套接字地址结构
    struct sockaddr {
    unsigned short sa_family; // 套接字地址簇类型,为AF_INET
    char sa_data[14];         // 套接字地址数据(14位的协议地址)
    };
  • IPV4套接字地址结构
    struct sockaddr_in{
    short sin_family;         // 套接字地址簇类型,为AF_INET
    unsigned short sin_port;  // 端口号,网络字节序
    struct in_addr sin_addr;  // IP地址,网络字节序
    unsigned char sin_zero[8];// 填充字节
    };
  • IPV4地址结构
    struct in_addr {
    in_addr_t s_addr;
    };
  • IPV4地址类型
    typedef unsigned int in_addr_t;

socket操作

  1. 创建
    int socket(int domain, int type, int protocol)

    技术分享图片

2.关闭

    int close(int sockfd)
int shutdown(int sockfd,int howto)

技术分享图片
3.属性
设置

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen)

技术分享图片
技术分享图片
技术分享图片
技术分享图片
技术分享图片
获取

int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen)

技术分享图片
技术分享图片

4.绑定

int bind(int socket, const struct sockaddr* address, socklen_t address_len)

技术分享图片

5.监听

int listen(int sockfd, int backlog)

技术分享图片

6.连接

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

技术分享图片
7.接收

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

技术分享图片
8.接受(分客户端和服务端)

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

技术分享图片

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

技术分享图片
如果不需要获取客户端套接字地址,后面两个参数设置为NULL

9.发送(分客户端和服务端)

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

技术分享图片

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

技术分享图片

10.接收

ssize_t read(int fd, void *buf, size_t len);

技术分享图片

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

技术分享图片

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen)

技术分享图片

实践
1.特殊地址设置
技术分享图片
2.原则
客户端/发送端
必须指定连接/发送的IP(广播地址、回环地址或者某个具体地址)。
必须指定连接/发送的port。
服务器/接受端
IP指定为通配地址、回环地址或者某个具体地址。
必须指定绑定监听/接受的port。
netstat 查看网络连接状态、socket端口打开状态

技术分享图片

代码实现大纲图:
技术分享图片

功能:
实现简单的服务端与服务器的交互
服务器端

#include<iostream>
#include<arpa/inet.h>
#nclude<unistd.h>
#include<strings.h>
using namespace std;

void show_connect(int fd){
        struct sockaddr_in  local_addr;
        socklen_t local_addr_len=sizeof(local_addr);
        bzero(&local_addr,local_addr_len);
        getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
            cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;

            struct sockaddr_in remote_addr;
            socklen_t remote_addr_len=sizeof(remote_addr);
            bzero(&remote_addr,remote_addr_len);
            getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
            cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}

void* read_msg(void* fd){
        int connfd=*(int*)fd;
        while(true){
          //读数据
            char buffer[1024]={0};
            int len=recv(connfd,buffer,sizeof(buffer),0);
            if(len==0){
                cout<<"client exit"<<endl;
                break;
            }else{
                cout<<"client:"<<buffer<<endl;
            }
        }
}
void* write_msg(void* fd){
         int connfd=*(int*)fd;
         while(true){
         //写数据
         string message;
         getline(cin,message);
         send(connfd,mesaage.c_str(),message.szie()+1,0);
         }
}
//./server ip port
int  main(int argc,char* argv[]){
        if(argc!=3){
            cout<<"usage:"<<argv[0]<<"Ip port"<<endl;
            return 1;
        }

        //1.监听套接字
        int listenfd=socket(AF_INET,SOCK_STREAM,0);
        if(listenfd==-1){
         cout<<"listen socket error"<<endl;
         return 1;
        }

        //2.绑定

        struct sockaddr_in local_addr;
        local_addr.sin_family=AF_INET;//协议
        local_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
        local_addr.sin_port=htons(atoi(argv[2]));//端口号

        if(-1==bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
        cout<<"bind error"<<endl;
        return 1;
        }else{
          cout<<"bind success"<<endl;
        }

        //3.监听设置
        if(listen(listenfd,10)==-1){
            cout<<"listen error"<<endl;
            return 1;
        }else{
           cout<<"listen success"<<endl;
        }
        //4.等待接收
        struct sockaddr_in remote_addr;
        bzero(&remote_addr,sizeof(remote_addr));
        socklen_t remote_addr_len=sizeof(remote_addr);
        int connfd=accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
        if(connfd==-1){
           cout<<"accept error"<<endl;
             return 1;
        }else{
          cout<<"accept success"<<endl;
            cout<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
            show_connfd(connfd);
        }

        pthread_t tids[2];
        pthread_create(tids,NULL,write_msg,&connfd);
        pthread_create(tids+1,NULL,read_msg,&connfd);

        for(auto tid:tids){
         pthread_join(tid,NULL);
        }

        //关闭套接字
        close(connfd);
        close(listenfd);        
}

客户端

#include<iostream>
#include<arpa/inet.h>
#nclude<unistd.h>
#include<strings.h>
using namespace std;

void show_connect(int fd){
//获取本地址和端口
        struct sockaddr_in  local_addr;
        socklen_t local_addr_len=sizeof(local_addr);
        bzero(&local_addr,local_addr_len);
        getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
            cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;
        //获取远程地址和端口
            struct sockaddr_in remote_addr;
            socklen_t remote_addr_len=sizeof(remote_addr);
            bzero(&remote_addr,remote_addr_len);
            getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
            cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}

void* read_msg(void* fd){
        int connfd=*(int*)fd;
        while(true){
          //读数据
            char buffer[1024]={0};
            int len=read(connfd,buffer,sizeof(buffer));
            if(len==0){
                cout<<"server exit"<<endl;
                break;
            }else{
                cout<<"server:"<<buffer<<endl;
            }
        }
}
void* write_msg(void* fd){
         int connfd=*(int*)fd;
         while(true){
         //发送消息
         string message;
         getline(cin,message);
         write(connfd,mesaage.c_str(),message.szie()+1);
         }
}
//./client ip port
int  main(int argc,char* argv[]){
        if(argc!=3){
            cout<<"usage:"<<argv[0]<<"Ip port"<<endl;
            return 1;
        }

        //1.创建套接字
        int connfd=socket(AF_INET,SOCK_STREAM,0);
        if(connfd==-1){
         cout<<" socket error"<<endl;
         return 1;
        }

        //2连接服务器

        struct sockaddr_in remote_addr;
        remote_addr.sin_family=AF_INET;//协议
        remote_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
        remote_addr.sin_port=htons(atoi(argv[2]));//端口号

        if(-1==connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
        cout<<"connect error"<<endl;
        return 1;
        }else{
          cout<<"connect success"<<endl;
            show_connect(connfd);
        }

        pthread_t tids[2];
        pthread_create(tids,NULL,write_msg,&connfd);
        pthread_create(tids+1,NULL,read_msg,&connfd);

        for(auto tid:tids){
         pthread_join(tid,NULL);
        }

        //关闭套接字
        close(connfd);
      return 0;
}

基于tcp/ip实现
功能:服务端实现发送信息到所有客户端 客户端传消息给服务端 让服务端帮转消息给除自己的所有客户端

服务器端

#include<iostream>
#include<arpa/inet.h>
#nclude<unistd.h>
#include<strings.h>
using namespace std;

void show_connect(int fd){
        struct sockaddr_in  local_addr;
        socklen_t local_addr_len=sizeof(local_addr);
        bzero(&local_addr,local_addr_len);
        getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
            cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;

            struct sockaddr_in remote_addr;
            socklen_t remote_addr_len=sizeof(remote_addr);
            bzero(&remote_addr,remote_addr_len);
            getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
            cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}

./server ip port
int  main(int argc,char* argv[]){
        if(argc!=3){
            cout<<"usage:"<<argv[0]<<"Ip port name"<<endl;
            return 1;
        }

        //1.监听套接字
        int listenfd=socket(AF_INET,SOCK_STREAM,0);
        if(listenfd==-1){
         cout<<"listen socket error"<<endl;
         return 1;
        }
        //设置端口重复利用
         int  flag=1; setsockopt(listenfd,SQL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));

        //2.绑定

        struct sockaddr_in local_addr;
        local_addr.sin_family=AF_INET;//协议
        local_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
        local_addr.sin_port=htons(atoi(argv[2]));//端口号

        if(-1==bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
        cout<<"bind error"<<endl;
        return 1;
        }else{
          cout<<"bind success"<<endl;
        }

        //3.监听设置
        if(listen(listenfd,10)==-1){
            cout<<"listen error"<<endl;
            return 1;
        }else{
           cout<<"listen success"<<endl;
        }

        vector<int> fds;
        thread([&fds]{
          while(true){
              string message;
                getline(cin,message);
                message="广告"+message;
                for(auto fd:fds){
                  write(fd,message.c_str(),message.size(0+1);
                }
            }
        }).detach();

        //4.等待接收
        while(true){
        struct sockaddr_in remote_addr;
        bzero(&remote_addr,sizeof(remote_addr));
        socklen_t remote_addr_len=sizeof(remote_addr);
        int connfd=accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
        if(connfd==-1){
           cout<<"accept error"<<endl;
             return 1;
        }else{
          cout<<"accept success"<<endl;
            cout<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
            show_connfd(connfd);
            fds.push_back(connfd);
        }

        thread([connfd,&fds]{
          while(true){
              char buffer[1024]={0};
                int n=read(connfd,buffer,1024);//读取客户端发过来的消息
                if(n==0){
                 break;
                }else{
                  for(auto fd:fds){  //发送消息给除了自己的所有客户端
                      if(fd==connfd) continue;
                        write(fd,buffer,1024);
                    }
                }
            }

        }).detach();

        close(listenfd);        
}

客户端

#include<iostream>
#include<arpa/inet.h>
#nclude<unistd.h>
#include<strings.h>
using namespace std;

string name;

void show_connect(int fd){
//获取本地址和端口
        struct sockaddr_in  local_addr;
        socklen_t local_addr_len=sizeof(local_addr);
        bzero(&local_addr,local_addr_len);
        getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
            cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;
        //获取远程地址和端口
            struct sockaddr_in remote_addr;
            socklen_t remote_addr_len=sizeof(remote_addr);
            bzero(&remote_addr,remote_addr_len);
            getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
            cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}

//./client ip port
int  main(int argc,char* argv[]){
        if(argc!=4){
            cout<<"usage:"<<argv[0]<<"Ip port name"<<endl;
            return 1;
        }
        name=argv[3];
        //1.创建套接字
        int connfd=socket(AF_INET,SOCK_STREAM,0);
        if(connfd==-1){
         cout<<" socket error"<<endl;
         return 1;
        }

        //2连接服务器

        struct sockaddr_in remote_addr;
        remote_addr.sin_family=AF_INET;//协议
        remote_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
        remote_addr.sin_port=htons(atoi(argv[2]));//端口号

        if(-1==connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
        cout<<"connect error"<<endl;
        return 1;
        }else{
          cout<<"connect success"<<endl;
            show_connect(connfd);
        }

thread([=]{
  while(true){
      string message;
         getline(cin,message);
         message =name+":"+message;
         write(connfd,mesaage.c_str(),message.szie()+1);
    }
}).detach();

thread([=]{
 while(true){
    char buffer[1024]={0};
            int len=read(connfd,buffer,sizeof(buffer));
            if(len==0){
                cout<<"server exit"<<endl;
                break;
            }else{
                cout<<"server:"<<buffer<<endl;
            }
 }
}).detach();

        //关闭套接字
        close(connfd);
      return 0;
}

socket编程 --pthread(TCP/IP)

原文:https://blog.51cto.com/14569275/2538214

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!