linux c++ socket

http://www.cnblogs.com/diligenceday/p/6241021.html



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多線程

  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;
}
複製代碼

  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;
}
複製代碼

 

  參考

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

  EOF

 

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

天道酬勤

發佈了84 篇原創文章 · 獲贊 110 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章