谭兄

导航

 

套接字概述

在Linux中,一切都是文件. Linux 中的网络编程通过socket接口进行,   socket是一种特殊的I/0接口, 也是一种文件描述符. 常用的进程之间通信.   下图是使用TCP协议的通信过程 :

 

三次握手建立连接

 

 

 

四次挥手断开连接

 

 

这里通过实现两个例子了解一些常用API的用法, 不废话, 直接上代码.

 

1.回声客户端

服务端代码

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

#define            PORT                4321        //端口号
#define            BUFFER_SIZE            1024        //缓冲区大小    
#define            MAX_QUE_CONN_NM        5            //最大请求队列

/* 处理客户端请求 */
void *conn_hand(void *arg){
    
    int client_fd = *(int *)arg;
    int recvbytes, sendbytes;
    char buf_recv[BUFFER_SIZE] = {0}, buf_send[BUFFER_SIZE];

    while(1){
    
        /* 调用recv()函数, 接受客户端请求. 从缓冲区中读取. */
        if((recvbytes = recv(client_fd, buf_recv, BUFFER_SIZE, 0)) == -1){
            perror("recv");
            break;
        }
        printf("receive from client: %s\n", buf_recv);

        /* 退出 */
        if(strcmp(buf_recv, "quit") == 0) break;

        /* 向客户端发送数据  这里只是写入缓冲区, 由TCP协议发送至网络中*/
        if(send(client_fd, buf_recv, recvbytes, 0) == -1){
            perror("send");
            break;
        }
        memset(buf_recv, 0, BUFFER_SIZE);

    }
    printf("terminating current connect...\n");
    close(client_fd);
    pthread_exit(NULL);
}

int main(void){

    struct sockaddr_in server_sockaddr, client_sockaddr;
    int sin_size;
    int sockfd, client_fd;

    /* 建立socket连接 */
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("socket");
        exit(1);
    }
    printf("socket id=%d\n", sockfd);
    
    /* 设置sockaddr_in 结构体参数 */
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(PORT);
    server_sockaddr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(server_sockaddr.sin_zero),8) ;

    /* 允许重复本地址绑定套接字 */
    int i = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));

    /* 绑定函数bind() */
    if(bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) == -1){
        perror("bind");
        exit(1);
    }
    printf("bind success!\n");
    
    /* 调用listen函数监听, 创建未处理请求队列 */
    if(listen(sockfd, MAX_QUE_CONN_NM) == -1){
        perror("listen");
        exit(1);
    }
    printf("listening port:%d ...\n", PORT);
   
    sin_size = sizeof(client_sockaddr);
    /* 循环接收客户端请求 */
    while(1){
        pthread_t tid;

        client_fd = accept(sockfd, (struct sockaddr *)&client_sockaddr, &sin_size);
        
        /* 创建新线程处理客户端请求*/
        if(pthread_create(&tid, NULL, conn_hand, &client_fd) == -1){
            perror("pthread_create");
            break;
        }
    }
    close(sockfd);
    exit(0);
}
View Code  

客户端代码

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

#define                PORT                4321            //端口
#define                BUFFER_SIZE            1024            //缓冲区大小

int main(int argc, char *argv[]){

    int sockfd, sendbytes, recvbytes;
    char buf_recv[BUFFER_SIZE], buf_send[BUFFER_SIZE];
    struct hostent *host;
    struct sockaddr_in serv_addr;

    if(argc != 2){
        fprintf(stderr, "usage: ./client <ip address>\n");
        exit(1);
    }

    /* 地址解析函数 */
    if((host = gethostbyname(argv[1])) == NULL){
        perror("gethostbyname");
        exit(1);
    }
    
    /* 设置sockaddr_in结构体参数 */
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
    bzero(&(serv_addr.sin_zero), 8);
    
    /* 创建socket */
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("socket");
        exit(1);
    }

    /*发起连接 */
    if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1){
        perror("connect");
        exit(1);
    }

    //循环发送请求
    while(1){
        /* 发送消息 */
        printf("sent to server:");
        scanf("%s", buf_send);

        if((sendbytes = send(sockfd, buf_send, strlen(buf_send), 0)) == -1){
            perror("send");
            exit(1);
        }

        if(strcmp(buf_send, "quit") == 0) break;

        /* 读取回送消息 */
        if((recvbytes = recv(sockfd, buf_recv, BUFFER_SIZE, 0)) > 0){
            printf("receive from server : %s\n", buf_recv);
        }
        
    }

    close(sockfd);
    exit(0);
}
View Code

编译运行

服务端
$ gcc server.c -o server -lpthread
$ ./server
socket id=3
bind success!
listening port:4321 ...
receive from client: 
客户端
$ gcc client.c -o client -lpthread $ ./client 127.0.0.1 sent to server:1 receive from server : 1 sent to server:quit

 

 

2.文件传输

服务端代码

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

#define            PORT                4321        //端口号
#define            BUFFER_SIZE            1024        //缓冲区大小    
#define            MAX_QUE_CONN_NM        5            //最大请求队列

int main(void){

    struct sockaddr_in server_sockaddr, client_sockaddr;
    int sin_size, recvbytes;
    int sockfd, client_fd;
    FILE *fp = fopen("file.txt", "rb");
    if(fp ==NULL){
        perror("file");
        exit(1);
    }


    /* 建立socket连接 */
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("socket");
        exit(1);
    }
    printf("socket id=%d\n", sockfd);
    
    /* 设置sockaddr_in 结构体参数 */
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(PORT);
    server_sockaddr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(server_sockaddr.sin_zero),8) ;
    
    int i = 1;    /* 允许重复使用本地地址与套接字绑定 */
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));

    /* 绑定函数bind() */
    if(bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) == -1){
        perror("bind");
        exit(1);
    }
    printf("bind success!\n");
    
    /* 调用listen函数监听, 创建未处理请求队列 */
    if(listen(sockfd, MAX_QUE_CONN_NM) == -1){
        perror("listen");
        exit(1);
    }
    printf("listening port:%d ...\n", PORT);

    /* 发送数据 */
    sin_size = sizeof(client_sockaddr);
    char buf_send[BUFFER_SIZE] = {0};
    if((client_fd = accept(sockfd, (struct sockaddr *)&client_sockaddr, &sin_size)) == -1){
            perror("accept");
            exit(1);
    }
    /* 向客户端发送数据  这里只是写入缓冲区, 由TCP协议发送至网络中*/
    int count;
    while((count = fread(buf_send, 1, BUFFER_SIZE, fp)) > 0){
        if(send(client_fd, buf_send, count, 0) == -1){
            perror("send");
            exit(1);
        }
    }

    /* 文件读取完毕, 断开输入流, 发送FIN数据包 */
    shutdown(client_fd, 2);
    /* 阻塞, 一旦客户端接收完毕,server收到FIN包, 继续向下执行  */
    recv(client_fd, buf_send, BUFFER_SIZE, 0);

    fclose(fp);
    close(client_fd);
    close(sockfd);
    exit(0);
}
View Code

客户端代码

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

#define                PORT                4321            //端口
#define                BUFFER_SIZE            1024            //缓冲区大小

int main(int argc, char *argv[]){

    int sockfd, sendbytes, recvbytes;
    struct hostent *host;
    struct sockaddr_in serv_addr;
    FILE *fp;
    fp = fopen("file_download.txt", "wb");

    if(fp ==NULL){
        perror("file");
        exit(1);
    }

    if(argc < 2){
        fprintf(stderr, "USAGE: ./client Hostname(or ip address) Text\n");
        exit(1);
    }



    /* 地址解析函数 */
    if((host = gethostbyname(argv[1])) == NULL){
        herror("gethostbyname");
        exit(1);
    }
    
    /* 设置sockaddr_in结构体参数 */
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
    bzero(&(serv_addr.sin_zero), 8);
    
    /* 创建socket */
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("socket");
        exit(1);
    }

    
    /*发起连接 */
    if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1){
        perror("connect");
        exit(1);
    }

    /* 接收文件 */
    char buf_recv[BUFFER_SIZE] = {0};
    while((recvbytes = recv(sockfd, buf_recv, BUFFER_SIZE, 0)) > 0){
        fwrite(buf_recv, recvbytes, 1, fp);
    }

    printf("文件接收完毕\n");

    fclose(fp);
    close(sockfd);
    exit(0);
}
View Code

 

posted on 2017-04-29 19:44  谭兄  阅读(230)  评论(0编辑  收藏  举报