[C++] Linux TCP Socket 实例- 阻塞


Linux平台 TCP Socket通信实例,发现用代码注释记笔记也不错

TCP server 阻塞

  1 // 两个进程通过socket进行通信,client需要知道server的,server却不需要实现知道client的。
  2 // socket需要知道type和address domain;
  3 // address domain:unix domain用于同主机进程间,通过文件系统实现;Internet domain用于两台机器间,需要IP和Port信息。一般2000以下的port保留。
  4 // socket type:stream(意味着持续读取,TCP是一种协议)、datagram(一次需要读完整个信息,UDP是一种协议)。
  5 
  6 // port复用机制的理解
  7 
  8 /**
  9 stream server
 10 1.socket
 11 2.bind
 12 3.listen
 13 4.accept
 14 */
 15 #include <cstdlib>              /* exit() */
 16 #include <cstdio>               /* perror(): 打印信息+发生错误的原因,可用于定位。 */
 17 #include <cstring>              /* memset memcpy*/
 18 #include <iostream>             /* cin cout */
 19 #include <sys/types.h>          /* 为了满足一些 BSD系统添加头文件*/
 20 #include <sys/socket.h>         /* socket(); listen(); baccept(); socklen_t */
 21 #include <netinet/in.h>         /* struct sockaddr_in: 保存socket信息; ntohl(), ntohs(), htonl() and htons()*/
 22 #include <unistd.h>             /* read() write(), 不是C语言范畴,所以没有cxxxx的实现 */
 23     // http://man7.org/linux/man-pages/man2/read.2.html
 24     // http://man7.org/linux/man-pages/man2/write.2.html
 25 
 26 /**
 27 \brief  错误处理函数
 28 */
 29 void tzError(const char *msg)
 30 {
 31     perror(msg);
 32     exit(1);    // 一般不同原因不同的exit code更为规范
 33 }
 34 
 35 /**
 36 \brief  主函数
 37 */
 38 int main(int argc, char *argv[]){
 39     // 参数check
 40     if (argc < 2) {
 41         fprintf(stderr,"ERROR, no [port] arg provided\n");
 42         exit(1);
 43     }
 44     // 生成socke + check
 45     int sockfd;
 46     sockfd = socket(AF_INET, SOCK_STREAM, 0);
 47         // int socket(int domain, int type, int protocol);
 48         // http://man7.org/linux/man-pages/man2/socket.2.html
 49         // domain:
 50         //      AF_UNIX     用于本地通信
 51         //      AF_INET     IPv4
 52         //      AF_INET6    IPv6
 53         // type:
 54         //      SOCK_STREAM     面向连接通信
 55         //      SOCK_DGRAM      面向无连接通信
 56         // protocol:
 57         //      SOCK_NONBLOCK   非阻塞
 58         //      SOCK_CLOEXEC    子类不继承父类的socket fd
 59         // Return:
 60         //      建立的socket:对于server用于监听,对于client用于向指定位置发送
 61     if (sockfd < 0){
 62         tzError("socket()");
 63     }
 64     // bind socket + check
 65     int port_no = atoi(argv[1]);
 66     struct sockaddr_in serv_addr;
 67     serv_addr.sin_family = AF_INET;             // IPv4
 68     serv_addr.sin_addr.s_addr = INADDR_ANY;     // 相当于inet_addr("0.0.0.0"),所有网卡。
 69     serv_addr.sin_port = htons(port_no);         // 需要网络序转换
 70     int bind_ret = bind(sockfd, 
 71                     (struct sockaddr*)&serv_addr, 
 72                     sizeof(serv_addr));
 73         // int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
 74         // http://man7.org/linux/man-pages/man2/bind.2.html
 75         // socket()产生sockdf,有了name space(address family)但是没有具体地址,bind完成此任务
 76     if( bind_ret<0 ){
 77         tzError("bind()");
 78     }
 79     // listen
 80     listen(sockfd,5);
 81         // int listen(int sockfd, int backlog);
 82         // http://man7.org/linux/man-pages/man2/listen.2.html
 83         // listen让sockfd对应的socket成为被动socket,用于accetp
 84         // backlog: 最大可以入队等待处理的连接数量。如果大于128(somaxconn)可能被内核截断,cat /proc/sys/net/core/somaxconn
 85         // 如果尝试connect的链接超过backlog,client收到ECONNREFUSED错误,如果有重传机制可能忽略此错误。
 86     // accept + check
 87     struct sockaddr_in client_addr;
 88     socklen_t clilen_len = sizeof(client_addr);
 89     int new_sockfd = accept(sockfd, 
 90                  (struct sockaddr *) &client_addr, 
 91                  &clilen_len);
 92         // int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
 93         // http://man7.org/linux/man-pages/man2/accept.2.html
 94         // 用于面向连接socket(SOCK_STREAM, SOCK_SEQPACKET),提取队列中第一个请求,创建新的connected socket
 95         // 返回新创建的socket的fd,原始的被动sockfd不受影响。
 96         // addr: socketaddr指针,记录peer的信息,信息格式取决于socket的定义。
 97             // 如果等待队列为空,且socket没有设置nonblocking-->阻塞等待;
 98             // 如果等待队列为空,且socket设置nonblocking,返回错误:EAGAIN or EWOULDBLOCK
 99         
100             // 为了处理对socket的新的connect,可使用:select(2), poll(2), or epoll(7)-->有尝试连接的请求会出触发"readable event"
101             // 也可以通过socket()设置发送SIGIO中断。
102         // addrlen:传入传输参数,实际的大小会重新保存到addrlen中
103     if (new_sockfd < 0) 
104           tzError("accept()");
105     // 接收-发送信息
106 #define RECV_BUF_SIZE   256
107     char buffer[RECV_BUF_SIZE];
108     std::memset(buffer, 0, RECV_BUF_SIZE);  // 用0进行set
109     int valread = read( new_sockfd , buffer, RECV_BUF_SIZE);
110     std::cout << "read:" << valread << "char, content: " << buffer << std::endl;
111     write(new_sockfd , "get msg", 7);
112     // close sockets
113     close(new_sockfd); 
114     close(sockfd);
115 
116     return 0;
117 }
118 
119 // ref:
120 //      https://www.cnblogs.com/fuchongjundream/p/3914696.html
121 //      http://www.linuxhowtos.org/C_C++/socket.htm
122 //      

TCP Client - 单次连接发送接收测试

  1 // 两个进程通过socket进行通信,client需要知道server的,server却不需要实现知道client的。
  2 // socket需要知道type和address domain;
  3 // address domain:unix domain用于同主机进程间,通过文件系统实现;Internet domain用于两台机器间,需要IP和Port信息。一般2000以下的port保留。
  4 // socket type:stream(意味着持续读取,TCP是一种协议)、datagram(一次需要读完整个信息,UDP是一种协议)。
  5 
  6 // port复用机制的理解
  7 
  8 /**
  9 stream client
 10 1.socket
 11 2.connect
 12 */
 13 #include <cstdlib>              /* exit() */
 14 #include <cstdio>               /* perror(): 打印信息+发生错误的原因,可用于定位。 */
 15 #include <cstring>              /* memset memcpy strcpy string.c_str()*/
 16 #include <iostream>             /* cin cout */
 17 #include <sys/types.h>          /* 为了满足一些 BSD系统添加头文件*/
 18 #include <sys/socket.h>         /* socket(); listen(); baccept(); socklen_t */
 19 // #include <netinet/in.h>         /* struct sockaddr_in: 保存socket信息; ntohl(), ntohs(), htonl() and htons()*/
 20 #include <netdb.h>              /* hostent,IP地址 */
 21 
 22 #include <unistd.h>             /* read() write(), 不是C语言范畴,所以没有cxxxx的实现 */
 23     // http://man7.org/linux/man-pages/man2/read.2.html
 24     // http://man7.org/linux/man-pages/man2/write.2.html
 25 
 26 /**
 27 \brief  错误处理函数
 28 */
 29 void tzError(const char *msg)
 30 {
 31     perror(msg);
 32     exit(1);    // 一般不同原因不同的exit code更为规范
 33 }
 34 
 35 /**
 36 \brief  主函数
 37 */
 38 int main(int argc, char *argv[]){
 39     // 参数check
 40     if (argc < 3) {
 41         tzError("ERROR, no [IP] [port] arg provided");
 42     }
 43     // 生成socke + check
 44     int sockfd;
 45     sockfd = socket(AF_INET, SOCK_STREAM, 0);
 46         // int socket(int domain, int type, int protocol);
 47         // http://man7.org/linux/man-pages/man2/socket.2.html
 48         // domain:
 49         //      AF_UNIX     用于本地通信
 50         //      AF_INET     IPv4
 51         //      AF_INET6    IPv6
 52         // type:
 53         //      SOCK_STREAM     面向连接通信
 54         //      SOCK_DGRAM      面向无连接通信
 55         // protocol:
 56         //      SOCK_NONBLOCK   非阻塞
 57         //      SOCK_CLOEXEC    子类不继承父类的socket fd
 58         // Return:
 59         //      建立的socket:对于server用于监听,对于client用于向指定位置发送
 60     if (sockfd < 0){
 61         tzError("socket()");
 62     }
 63     // connect + check
 64     struct hostent *server;
 65         // struct hostent {
 66         //     char  *h_name;            /* official name of host */
 67         //     char **h_aliases;         /* alias list */
 68         //     int    h_addrtype;        /* host address type */
 69         //     int    h_length;          /* length of address */
 70         //     char **h_addr_list;       /* list of addresses */
 71         // }
 72         // #define h_addr h_addr_list[0] /* for backward compatibility,第一个地址 */
 73     server = gethostbyname(argv[1]);
 74     if (server == NULL) {
 75         tzError("[IP] error");
 76     }
 77     int port_no = atoi(argv[2]);
 78     struct sockaddr_in serv_addr;
 79     memset(&serv_addr, 0, sizeof(serv_addr));
 80     serv_addr.sin_family = AF_INET;     // set type
 81     memcpy((char *)server->h_addr,      // set addr
 82         (char *)&serv_addr.sin_addr.s_addr,
 83         server->h_length);
 84     serv_addr.sin_port = htons(port_no); // set port
 85     int conntect_ret = connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
 86     if(conntect_ret<0){
 87         tzError("connect()");
 88     }
 89 
 90     // write and read
 91     std::cout << "msg>";
 92     std::string msg;
 93     std::cin >> msg;
 94 #define BUF_SIEE    128
 95     char buf[BUF_SIEE];
 96     memset(buf, 0, BUF_SIEE);
 97     strcpy(buf, msg.c_str());
 98     int write_n = write(sockfd, buf, msg.size());
 99     std::cout << write_n << " chars send." << std::endl;
100     memset(buf, 0, BUF_SIEE);   // 用于输出,依赖\0
101     int read_n = read(sockfd, buf, BUF_SIEE);
102     std::cout << buf << std::endl;
103     std::cout << read_n << " chars read." << std::endl;
104     
105     // close sockets
106     close(sockfd);
107 
108     return 0;
109 }
110 
111 // ref:
112 //      http://www.linuxhowtos.org/C_C++/socket.htm
113  

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM