linux:C++的socket编程

  基本的局域网聊天

  局域网聊天TCP服务端:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <thread>
#include <iostream>
#define PORT 7000
#define QUEUE 20
int conn;
void thread_task() {
}

int main() {
    //printf("%d\n",AF_INET);
    //printf("%d\n",SOCK_STREAM);
    int ss = socket(AF_INET, SOCK_STREAM, 0);
    //printf("%d\n",ss);
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(PORT);
    //printf("%d\n",INADDR_ANY);
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(ss, (struct sockaddr* ) &server_sockaddr, sizeof(server_sockaddr))==-1) {
        perror("bind");
        exit(1);
    }
    if(listen(ss, QUEUE) == -1) {
        perror("listen");
        exit(1);
    }

    struct sockaddr_in client_addr;
    socklen_t length = sizeof(client_addr);
    ///成功返回非负描述字,出错返回-1
    conn = accept(ss, (struct sockaddr*)&client_addr, &length);
    if( conn < 0 ) {
        perror("connect");
        exit(1);
    }

    char buffer[1024];
    //创建另外一个线程
    //std::thread t(thread_task);
    //t.join();
    //char buf[1024];
    //主线程
    while(1) {

        // memset(buf, 0 ,sizeof(buf));
        // if(fgets(buf, sizeof(buf),stdin) != NULL) {
        //     send(conn, buf, sizeof(buf), 0);    
        // }

        memset(buffer, 0 ,sizeof(buffer));
        int len = recv(conn, buffer, sizeof(buffer), 0);
        if(strcmp(buffer, "exit\n") == 0) break;
        printf("%s", buffer);
        //必须要有返回数据, 这样才算一个完整的请求
        send(conn, buffer, len , 0);
    }
    close(conn);
    close(ss);
    return 0;
}

  局域网聊天TCP客户端:

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

#define MYPORT  7000
#define BUFFER_SIZE 1024

int main()
{
    ///定义sockfd
    int sock_cli = socket(AF_INET,SOCK_STREAM, 0);

    ///定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(MYPORT);  ///服务器端口
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  ///服务器ip

    //连接服务器,成功返回0,错误返回-1
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }

    char sendbuf[BUFFER_SIZE];
    char recvbuf[BUFFER_SIZE];
    while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
    {
        send(sock_cli, sendbuf, strlen(sendbuf),0); ///发送
        if(strcmp(sendbuf,"exit\n")==0)
            break;
        recv(sock_cli, recvbuf, sizeof(recvbuf),0); ///接收
        fputs(recvbuf, stdout);

        memset(sendbuf, 0, sizeof(sendbuf));
        memset(recvbuf, 0, sizeof(recvbuf));
    }

    close(sock_cli);
    return 0;
}

 

  


  客户端服务端双向异步聊天源码

  以上的局域网聊天应用有一个很重要的缺点, 服务器只能显示客户端发送的消息, 却无法给客户端发送消息, 这个很尴尬;

  通过使用C中的select()函数, 实现一个异步聊天工具:

  异步聊天服务端代码:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
#define PORT 7000
#define QUEUE 20

int main() {
    fd_set rfds;
    struct timeval tv;
    int retval, maxfd;
    int ss = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(PORT);
    //printf("%d\n",INADDR_ANY);
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(ss, (struct sockaddr* ) &server_sockaddr, sizeof(server_sockaddr))==-1) {
        perror("bind");
        exit(1);
    }
    if(listen(ss, QUEUE) == -1) {
        perror("listen");
        exit(1);
    }

    struct sockaddr_in client_addr;
    socklen_t length = sizeof(client_addr);
    ///成功返回非负描述字,出错返回-1
    int conn = accept(ss, (struct sockaddr*)&client_addr, &length);
    if( conn < 0 ) {
        perror("connect");
        exit(1);
    }
    while(1) {
        /*把可读文件描述符的集合清空*/
        FD_ZERO(&rfds);
        /*把标准输入的文件描述符加入到集合中*/
        FD_SET(0, &rfds);
        maxfd = 0;
        /*把当前连接的文件描述符加入到集合中*/
        FD_SET(conn, &rfds);
        /*找出文件描述符集合中最大的文件描述符*/    
        if(maxfd < conn)
            maxfd = conn;
        /*设置超时时间*/
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        /*等待聊天*/
        retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
        if(retval == -1){
            printf("select出错,客户端程序退出\n");
            break;
        }else if(retval == 0){
            printf("服务端没有任何输入信息,并且客户端也没有信息到来,waiting...\n");
            continue;
        }else{
            /*客户端发来了消息*/
            if(FD_ISSET(conn,&rfds)){
                char buffer[1024];    
                memset(buffer, 0 ,sizeof(buffer));
                int len = recv(conn, buffer, sizeof(buffer), 0);
                if(strcmp(buffer, "exit\n") == 0) break;
                printf("%s", buffer);
                //send(conn, buffer, len , 0);把数据回发给客户端
            }
            /*用户输入信息了,开始处理信息并发送*/
            if(FD_ISSET(0, &rfds)){
                char buf[1024];
                fgets(buf, sizeof(buf), stdin);
                //printf("you are send %s", buf);
                send(conn, buf, sizeof(buf), 0);    
            }
        }
    }
    close(conn);
    close(ss);
    return 0;
}

  异步聊天客户端代码:

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

#define MYPORT  7000
#define BUFFER_SIZE 1024
int main()
{
    int sock_cli;
    fd_set rfds;
    struct timeval tv;
    int retval, maxfd;

    ///定义sockfd
    sock_cli = socket(AF_INET,SOCK_STREAM, 0);
    ///定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(MYPORT);  ///服务器端口
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  ///服务器ip

    //连接服务器,成功返回0,错误返回-1
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }

    while(1){
        /*把可读文件描述符的集合清空*/
        FD_ZERO(&rfds);
        /*把标准输入的文件描述符加入到集合中*/
        FD_SET(0, &rfds);
        maxfd = 0;
        /*把当前连接的文件描述符加入到集合中*/
        FD_SET(sock_cli, &rfds);
        /*找出文件描述符集合中最大的文件描述符*/    
        if(maxfd < sock_cli)
            maxfd = sock_cli;
        /*设置超时时间*/
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        /*等待聊天*/
        retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
        if(retval == -1){
            printf("select出错,客户端程序退出\n");
            break;
        }else if(retval == 0){
            printf("客户端没有任何输入信息,并且服务器也没有信息到来,waiting...\n");
            continue;
        }else{
            /*服务器发来了消息*/
            if(FD_ISSET(sock_cli,&rfds)){
                char recvbuf[BUFFER_SIZE];
                int len;
                len = recv(sock_cli, recvbuf, sizeof(recvbuf),0);
                printf("%s", recvbuf);
                memset(recvbuf, 0, sizeof(recvbuf));
            }
            /*用户输入信息了,开始处理信息并发送*/
            if(FD_ISSET(0, &rfds)){
                char sendbuf[BUFFER_SIZE];
                fgets(sendbuf, sizeof(sendbuf), stdin);
                send(sock_cli, sendbuf, strlen(sendbuf),0); //发送
                memset(sendbuf, 0, sizeof(sendbuf));
            }
        }
    }

    close(sock_cli);
    return 0;
}

 


  局域网内服务端和有限个客户端聊天源码

   以上的局域网聊天只能支持一个用户, 我们还要改改, 必须是支持多用户的聊天室:

  局域网TCP多人聊天服务端代码:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
#include <thread>
#define PORT 7000
#define QUEUE 20
int ss;
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
int conns[2] = {};
int z = 0;
void thread_fn() {
    //成功返回非负描述字,出错返回-1
    int conn = accept(ss, (struct sockaddr*)&client_addr, &length);
    if( conn < 0 ) {
        perror("connect");
        exit(1);
    }
    //把连接保存到临时数组中;
    conns[z] = conn;
    z++;

    fd_set rfds;
    struct timeval tv;
    int retval, maxfd;
    while(1) {
        /*把可读文件描述符的集合清空*/
        FD_ZERO(&rfds);
        /*把标准输入的文件描述符加入到集合中*/
        FD_SET(0, &rfds);
        maxfd = 0;
        /*把当前连接的文件描述符加入到集合中*/
        FD_SET(conn, &rfds);
        /*找出文件描述符集合中最大的文件描述符*/    
        if(maxfd < conn)
            maxfd = conn;
        /*设置超时时间*/
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        /*等待聊天*/
        retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
        if(retval == -1){
            printf("select出错,客户端程序退出\n");
            break;
        }else if(retval == 0){
            printf("服务端没有任何输入信息,并且客户端也没有信息到来,waiting...\n");
            continue;
        }else{
            /*客户端发来了消息*/
            if(FD_ISSET(conn,&rfds)){
                char buffer[1024];    
                memset(buffer, 0 ,sizeof(buffer));
                int len = recv(conn, buffer, sizeof(buffer), 0);
                if(strcmp(buffer, "exit\n") == 0) break;
                printf("%s", buffer);
                //send(conn, buffer, len , 0);把数据回发给客户端
            }
            /*用户输入信息了,开始处理信息并发送*/
            if(FD_ISSET(0, &rfds)){
                char buf[1024];
                fgets(buf, sizeof(buf), stdin);
                //printf("you are send %s", buf);
                for(int i=0; i<z; i++) {
                    send(conns[i], buf, sizeof(buf), 0);
                }    
            }
        }
    }
    close(conn);
}
void thread_select(int conn) {
}
int main() {
    ss = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(PORT);
    //printf("%d\n",INADDR_ANY);
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(ss, (struct sockaddr* ) &server_sockaddr, sizeof(server_sockaddr))==-1) {
        perror("bind");
        exit(1);
    }
    if(listen(ss, QUEUE) == -1) {
        perror("listen");
        exit(1);
    }
    std::thread t(thread_fn);
    std::thread t1(thread_fn);
    t.join();
    t1.join();
    close(ss);
    return 0;
}

  局域网TCP多人聊天客户端代码:

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

#define MYPORT  7000
#define BUFFER_SIZE 1024
int main()
{
    int sock_cli;
    fd_set rfds;
    struct timeval tv;
    int retval, maxfd;

    ///定义sockfd
    sock_cli = socket(AF_INET,SOCK_STREAM, 0);
    ///定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(MYPORT);  ///服务器端口
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  ///服务器ip

    //连接服务器,成功返回0,错误返回-1
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }

    while(1){
        /*把可读文件描述符的集合清空*/
        FD_ZERO(&rfds);
        /*把标准输入的文件描述符加入到集合中*/
        FD_SET(0, &rfds);
        maxfd = 0;
        /*把当前连接的文件描述符加入到集合中*/
        FD_SET(sock_cli, &rfds);
        /*找出文件描述符集合中最大的文件描述符*/    
        if(maxfd < sock_cli)
            maxfd = sock_cli;
        /*设置超时时间*/
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        /*等待聊天*/
        retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
        if(retval == -1){
            printf("select出错,客户端程序退出\n");
            break;
        }else if(retval == 0){
            printf("客户端没有任何输入信息,并且服务器也没有信息到来,waiting...\n");
            continue;
        }else{
            /*服务器发来了消息*/
            if(FD_ISSET(sock_cli,&rfds)){
                char recvbuf[BUFFER_SIZE];
                int len;
                len = recv(sock_cli, recvbuf, sizeof(recvbuf),0);
                printf("%s", recvbuf);
                memset(recvbuf, 0, sizeof(recvbuf));
            }
            /*用户输入信息了,开始处理信息并发送*/
            if(FD_ISSET(0, &rfds)){
                char sendbuf[BUFFER_SIZE];
                fgets(sendbuf, sizeof(sendbuf), stdin);
                send(sock_cli, sendbuf, strlen(sendbuf),0); //发送
                memset(sendbuf, 0, sizeof(sendbuf));
            }
        }
    }

    close(sock_cli);
    return 0;
}

 


  完美异步聊天服务端和客户端源码

  以上的多客户聊天不是很好, 因为只允许两个客户端连接, 体验非常差, 如果支持无限个客户端聊天的话那该多好啊, 哈哈, 这个也是可以的, 我们只要使用c++的list即可, 它是可以自增的数组(其实算是链表), 引用 头文件<list>即可:

  无限个客户聊天的 服务端代码:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
#include <thread>
#include <list>

#define PORT 7000
#define IP "127.0.0.1"

int s;
struct sockaddr_in servaddr;
socklen_t len;
std::list<int> li;

void getConn() {
    while(1){
        int conn = accept(s, (struct sockaddr*)&servaddr, &len);
        li.push_back(conn);
        printf("%d\n", conn);
    }
}

void getData() {
    struct timeval tv;
    tv.tv_sec = 2;
    tv.tv_usec = 0;
    while(1) {
        std::list<int>::iterator it;
        for(it=li.begin(); it!=li.end(); ++it){            
            fd_set rfds;    
            FD_ZERO(&rfds);
            int maxfd = 0;
            int retval = 0;
            FD_SET(*it, &rfds);
            if(maxfd < *it){
                maxfd = *it;
            }
            retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
            if(retval == -1){
                printf("select error\n");
            }else if(retval == 0) {
                //printf("not message\n");
            }else{
                char buf[1024];
                memset(buf, 0 ,sizeof(buf));
                int len = recv(*it, buf, sizeof(buf), 0);
                printf("%s", buf);
            }
        }
        sleep(1);

    }
}

void sendMess() {
    while(1) {
        char buf[1024];
        fgets(buf, sizeof(buf), stdin);
        //printf("you are send %s", buf);
        std::list<int>::iterator it;
        for(it=li.begin(); it!=li.end(); ++it){
            send(*it, buf, sizeof(buf), 0);
        }
    }
}

int main() {
    //new socket
    s = socket(AF_INET, SOCK_STREAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    servaddr.sin_addr.s_addr = inet_addr(IP);
    if(bind(s, (struct sockaddr* ) &servaddr, sizeof(servaddr))==-1) {
        perror("bind");
        exit(1);
    }
    if(listen(s, 20) == -1) {
        perror("listen");
        exit(1);
    }
    len = sizeof(servaddr);

    //thread : while ==>> accpet
    std::thread t(getConn);
    t.detach();
    //printf("done\n");
    //thread : input ==>> send
    std::thread t1(sendMess);
    t1.detach();
    //thread : recv ==>> show
    std::thread t2(getData);
    t2.detach();
    while(1){

    }
    return 0;
}

  无限个客户端连接的客户端代码:

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

#define MYPORT  7000
#define BUFFER_SIZE 1024
int main()
{
    int sock_cli;
    fd_set rfds;
    struct timeval tv;
    int retval, maxfd;

    ///定义sockfd
    sock_cli = socket(AF_INET,SOCK_STREAM, 0);
    ///定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(MYPORT);  ///服务器端口
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  ///服务器ip

    //连接服务器,成功返回0,错误返回-1
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }

    while(1){
        /*把可读文件描述符的集合清空*/
        FD_ZERO(&rfds);
        /*把标准输入的文件描述符加入到集合中*/
        FD_SET(0, &rfds);
        maxfd = 0;
        /*把当前连接的文件描述符加入到集合中*/
        FD_SET(sock_cli, &rfds);
        /*找出文件描述符集合中最大的文件描述符*/    
        if(maxfd < sock_cli)
            maxfd = sock_cli;
        /*设置超时时间*/
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        /*等待聊天*/
        retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
        if(retval == -1){
            printf("select出错,客户端程序退出\n");
            break;
        }else if(retval == 0){
            printf("客户端没有任何输入信息,并且服务器也没有信息到来,waiting...\n");
            continue;
        }else{
            /*服务器发来了消息*/
            if(FD_ISSET(sock_cli,&rfds)){
                char recvbuf[BUFFER_SIZE];
                int len;
                len = recv(sock_cli, recvbuf, sizeof(recvbuf),0);
                printf("%s", recvbuf);
                memset(recvbuf, 0, sizeof(recvbuf));
            }
            /*用户输入信息了,开始处理信息并发送*/
            if(FD_ISSET(0, &rfds)){
                char sendbuf[BUFFER_SIZE];
                fgets(sendbuf, sizeof(sendbuf), stdin);
                send(sock_cli, sendbuf, strlen(sendbuf),0); //发送
                memset(sendbuf, 0, sizeof(sendbuf));
            }
        }
    }

    close(sock_cli);
    return 0;
}

 


 

  局域网通过UDP实现服务端和客户端的通信, UDP的服务端不需要执行listen函数accept函数

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#define PORT_SERV 8888
#define BUFF_LEN 256
void udpserv_echo(int s, struct sockaddr* client);
int main() {
    int s;
    struct sockaddr_in addr_serv, addr_clie;
    s = socket(AF_INET, SOCK_DGRAM, 0);
    memset(&addr_serv, 0 , sizeof(addr_serv));
    addr_serv.sin_family = AF_INET;
    addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
    addr_serv.sin_port = htons(PORT_SERV);
    bind(s, (struct sockaddr*)&addr_serv, sizeof(addr_serv));
    udpserv_echo(s, (struct sockaddr*)&addr_clie);
    return 0;
}
void udpserv_echo(int s, struct sockaddr* client) {
    int n;
    char buff[BUFF_LEN];
    int len;
    //printf("%p\n",&recvfrom);
    while(1) {
        socklen_t length = sizeof(client);
        n = recvfrom(s, buff, BUFF_LEN, 0 , client, &length);
        printf("%s\n", buff);
        //strcpy(buff, "nice to see you");
        sendto(s, buff, n, 0, client, len);
    }
}

  UDP客户端代码, UDP客户端不需要connect函数, 但是执行sendto的时候需要指定 sockfd描述符:

#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT_SERV 8888
#define BUFF_LEN 256
void udpclient_echo(int s, struct sockaddr* serv) {
    char buff[BUFF_LEN];
    int len = sizeof(*serv);
    while(fgets(buff, BUFF_LEN, stdin)!=NULL) {
        sendto(s, buff, BUFF_LEN, 0, serv, len);       
    }
}
int main(int argc , char ** argv) {
    int s;
    struct sockaddr_in addr_serv;
    s = socket(AF_INET, SOCK_DGRAM, 0);
    memset(&addr_serv, 0 , sizeof(addr_serv));
    addr_serv.sin_family = AF_INET;
    //addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
    addr_serv.sin_addr.s_addr = inet_addr(argv[1]);
    addr_serv.sin_port = htons(PORT_SERV);
    udpclient_echo(s, (struct sockaddr*)&addr_serv);
    return 0;
}

  获取当前进程的ID:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(void) {
    pid_t pid,ppid;
    pid = getpid();
    ppid = getppid();
    printf("pid is %d;\nppid is %d; \n",pid, ppid);
    return 0;
}

  system语句的使用:

#include <stdlib.h>
#include <stdio.h>
int main(void) {
    int ret;
    ret = system("ping www.baidu.com");
    printf("%d\n", ret);
    return 0;
}

  C++定时器

  定时器, 这个是c++的语法, c的标准库中没有定时器:

#include <stdio.h>        //printf()
#include <unistd.h>        //pause()
#include <signal.h>        //signal()
#include <string.h>        //memset()
#include <sys/time.h>    //struct itimerval, setitimer()

static int count = 0;

void printMes(int signo)
{
    printf("Get a SIGALRM, %d counts!\n", ++count);
}

int main()
{
    int res = 0;
    struct itimerval tick;
    
    signal(SIGALRM, printMes);
    memset(&tick, 0, sizeof(tick));

    //Timeout to run first time
    tick.it_value.tv_sec = 1;
    tick.it_value.tv_usec = 0;

    //After first, the Interval time for clock
    tick.it_interval.tv_sec = 1;
    tick.it_interval.tv_usec = 0;
    setitimer(ITIMER_REAL, &tick, NULL);
    //if(setitimer(ITIMER_REAL, &tick, NULL) < 0)
            //printf("Set timer failed!\n");

    //When get a SIGALRM, the main process will enter another loop for pause()
    while(1)
    {
    }
    return 0;
} 

  select的使用,通过select可以实现定时器:

static void sleep_ms(unsigned int secs){
    struct timeval tval;
    tval.tv_sec=secs/1000;
    tval.tv_usec=(secs*1000)%1000000;
    select(0,NULL,NULL,NULL,&tval);
}

  select异步代码

  通过select,实现socket可读或者可写的时候,然后再搞事情:

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
    while(1) {
        fd_set rd;
        struct timeval tv;
        int err;

        FD_ZERO(&rd);
        FD_SET(0, &rd);

        tv.tv_sec = 5;
        tv.tv_usec = 0;
        err = select(1, &rd, NULL, NULL, &tv);
        if(err == -1) {
            perror("select error()\n");
        }else if(err == 0) {
            printf("no data is avaliable now\n");
        }else{
            if(FD_ISSET(0, &rd)) {
                char buf[1024];
                fgets(buf, sizeof(buf), stdin);
                printf("%s",buf);
            }
        }
    }
    return 0;
}

  pthead多线程

  没有参数的多线程 ,假设文件名字为:ph.c ,那么要通过 gcc ph.c -o ph -w -lphread ,进行编译:

#include <stdio.h>
#include <string.h>
#include <pthread.h>

void *pfn() {
    printf("run\n");
}

void main(int argc , char *argv[] ) {
    pthread_t pid, pid2;
    pthread_create(&pid, NULL, pfn, NULL);
    pthread_join(pid, NULL);
}

  pthead多线程编程, 使用pthead实现子程, 并给子程传递参数:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>

void* start(void* args) {
    printf("sub thread ; the args is %d\n", *((int *)args));
    return NULL;
}
int main(void) {
    pthread_t pt;
    int ret = -1;
    int times = 3;
    int run = 2;
    ret = pthread_create(&pt, NULL, start, &run);
    if(ret != 0) {
        printf("create error\n");
        return 1;
    }
    usleep(1);
    printf("main thread\n");
    pthread_join(pt, NULL);
    return 0;
}

 

  获取指定网卡的MAC地址和IP:

#include <net/ethernet.h>
#include <stdio.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/if.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void getMac(char *MAC, char *str) {
   char ifPath[256]="/sys/class/net/"; //默认网卡路径
    strcat(ifPath , str);
    strcat(ifPath ,"/address");
    //打开这个设备
    FILE *ff = fopen(ifPath,"r");
    fread(MAC,1, 17, ff);
    fclose(ff);
}
//根据网卡获取ip的通用函数
void getIp(unsigned char *ip, char *itf) {
    int fd;
    struct ifreq ifr;
    in_addr tIP ;

    fd = socket(AF_INET, SOCK_DGRAM, 0);    //using ioctl get IP address
    ifr.ifr_addr.sa_family = AF_INET;
    strcpy(ifr.ifr_name , (char*)itf);
    ioctl(fd, SIOCGIFADDR, &ifr);

    close(fd);

    tIP =((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
    memcpy((char*)ip , &tIP ,sizeof(in_addr));
    printf("ip is %s", inet_ntoa(tIP));
}

int main(int argc, char *argv[]) {
    struct sockaddr_ll device;
    char NetInterface[10];
    strcpy(NetInterface, argv[1]);
    int index = if_nametoindex ((const char*)NetInterface);
    printf("index is %d\n", index);

    //get MAC, 要设置初始值
    char MAC[18]={0};
    char end[] = "0";
    getMac(MAC, argv[1]);
    printf("%s\n", MAC);

    unsigned char ip[4];
    getIp(ip, argv[1]);
    printf("\n");
    return 0;
}

 

  C, fork语句的使用, fork返回值为0时说明运行在拷贝线程中:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
    pid_t pid;
    pid = fork();
    if( -1 == pid ) {
        printf("error \n");
    }else if( pid ==0 ) {
        printf(" fork value %d ; parent id : %d ; fork id : %d\n ", pid, getppid(), getpid());
    }else{
        printf(" run in parent scope, pid is %d \n", getpid());
    }
    return 0;
}

  通过使用fork,可以简化服务端的代码, 局域网聊天服务端代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>

const int MAX_LINE = 2048;
const int PORT = 6000;
const int BACKLOG = 10;
const int LISTENQ = 6666;
const int MAX_CONNECT = 20;

int main() {
    struct sockaddr_in serAddr, cliAddr;
    int listenFd, connFd;
    pid_t childPid;
    char buf[MAX_LINE];
    socklen_t client;

    listenFd = socket(AF_INET, SOCK_STREAM, 0);
    if(listenFd < 0){
        perror("socket error");
        exit(1);

    }
    bzero(&serAddr, sizeof(serAddr));
    serAddr.sin_family = AF_INET;
    serAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serAddr.sin_port = htons(PORT);
    if(bind(listenFd, (struct sockaddr*)&serAddr, sizeof(serAddr)) < 0) {
        perror("bind error");
        exit(1);
    };
    if(listen(listenFd, LISTENQ) < 0) {
        perror("listen error");
        exit(1);
    };
        printf("data");
    while(true) {
        client = sizeof(cliAddr);
        connFd = accept(listenFd, (struct sockaddr*)&cliAddr, &client);
        if(connFd < 0) {
            perror("accept error");
            exit(1);
        }
        childPid =fork();
        if(childPid == 0) {
            close(listenFd);
            char buf[MAX_LINE];
            while(read(connFd, buf, MAX_LINE) > 0) {
                printf("data is %s", buf);
                memset(buf, 0 ,sizeof(buf));
            };
        }
    }
    close(listenFd);
    return 0;
}

  客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>

const int MAX_LINE = 2048;
const int PORT = 6000;
const int BACKLOG = 10;
const int LISTENQ = 6666;
const int MAX_CONNECT = 20;

int main(int argc , char **argv) {
    int sockFd;
    struct sockaddr_in serAddr;
    if( argc != 2) {
        perror("args error");
        exit(1);
    }
    sockFd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockFd < 0) {
        perror("socket error");
        exit(1);
    }
    bzero(&serAddr, sizeof(serAddr));
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(PORT);
    printf("%s",argv[0]);
    //serAddr.sin_addr.s_addr = inet_addr(argv[1]);
    if(inet_pton(AF_INET , argv[1] , &serAddr.sin_addr) < 0)
    {
        printf("inet_pton error for %s\n",argv[1]);
        exit(1);
    }
    if(connect(sockFd, (struct sockaddr*)&serAddr, sizeof(serAddr)) < 0) {
        perror("connect error");
        exit(1);
    };
    char sendLine[MAX_LINE];
    while(fgets(sendLine, MAX_LINE, stdin)!=NULL) {
        write(sockFd, sendLine, strlen(sendLine));
    }
    close(sockFd);
    return 0;
}

   socket服务端:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

#define QUEUE 10
#define SIZE 256

int main() {
    //sock fd 
    int fd;
    struct sockaddr_in saddr, caddr;
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if( fd<0 ){
        perror("socket error");
        exit(1);
    }
    bzero(&saddr , sizeof(saddr));
    bzero(&caddr , sizeof(caddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(2000);
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);

    //bind 
    int bfd = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
    if( bfd<0 ){
        perror("bind error");
        exit(1);
    }
    //listen
    int lfd = listen(fd, QUEUE);
    if( lfd<0 ){
        perror("listen error");
        exit(1);
    }
    //accept
    socklen_t len = sizeof(caddr);
    int conn = accept(fd, (struct sockaddr *)&caddr, &len);
    if(conn < 0){
        perror("conn error");
        exit(1);
    }
    char buf[SIZE];

    while(read(conn, buf, SIZE) > 0) {
        //read
        printf("%s", buf);
        bzero(buf, SIZE);
    }


    close(fd);
    return 0;
}
View Code

  socket客户端:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>

#define SIZE 256

int main() {
    int fd;
    fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in saddr;
    bzero(&saddr, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(2000);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    int conn;
    conn = connect(fd, (struct sockaddr*)&saddr, sizeof(saddr));
    if( conn<0 ) {
        perror("error");
        exit(1);
    }
    char buf[SIZE];
    while(fgets(buf, SIZE, stdin)!=NULL) {
        printf("%s", buf);
        write(fd, buf, SIZE);
        bzero(buf, SIZE);
    }
    return 0;
}
View Code

 

  参考

  c++中Socket通信函数之select : http://blog.csdn.net/piaojun_pj/article/details/5991968/

  EOF

 

作者: NONO
出处:http://www.cnblogs.com/diligenceday/
QQ:287101329
微信:18101055830 

posted @ 2017-01-03 03:22  方方和圆圆  阅读(26076)  评论(2编辑  收藏  举报

再过一百年, 我会在哪里?