我们来试验一下socket发送和接受数据
一共有三个文件:mysocket.h、socketServer.c、socketClient.c
过程:
1.将这三个文件准备好,放到一个目录下
2.执行 gcc socketServer.c -o server.out
3.执行 gcc socketClient.c -o client.out
4.在一个终端窗口执行:./server.out,可以看到当前进程处于等待状态
5.再打开另一个终端窗口执行:./client.out 1
6.观察两个窗口的输出
下面是三个文件的源代码,在IDE里面报红不用管,按上面的过程去执行就好。

mysocket.h:

#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdarg.h>
#include <stdlib.h>

#define MAXLINE 4096
ssize_t      /* Read "n" bytes from a descriptor. */
readn(int fd, void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nread;
    char *ptr;

    ptr = vptr;
    nleft = n;
    while (nleft > 0) {
        if ( (nread = read(fd, ptr, nleft)) < 0) {
            if (errno == EINTR)
                nread = 0;  /* and call read() again */
            else
                return(-1);
        } else if (nread == 0)
            break;    /* EOF */

        nleft -= nread;
        ptr   += nread;
    }
    return n - nleft;  /* return >= 0 */
}

ssize_t      /* Write "n" bytes to a descriptor. */
writen(int fd, const void *vptr, size_t n)
{
    size_t  nleft;
    ssize_t  nwritten;
    const char *ptr;

    ptr = vptr;
    nleft = n;
    while (nleft > 0) {
        if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
            if (nwritten < 0 && errno == EINTR)
                nwritten = 0;  /* and call write() again */
            else
                return(-1);   /* error */
        }

        nleft -= nwritten;
        ptr   += nwritten;
    }
    return n;
}

static void err_doit(int, int, const char *, va_list);

/*
 * Nonfatal error related to a system call.
 * Print a message and return.
 */
void
err_ret(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
}


/*
 * Fatal error related to a system call.
 * Print a message and terminate.
 */
void
err_sys(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    exit(1);
}


/*
 * Fatal error unrelated to a system call.
 * Error code passed as explict parameter.
 * Print a message and terminate.
 */
void
err_exit(int error, const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, error, fmt, ap);
    va_end(ap);
    exit(1);
}


/*
 * Fatal error related to a system call.
 * Print a message, dump core, and terminate.
 */
void
err_dump(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    abort(); /* dump core and terminate */
    exit(1); /* shouldn't get here */
}


/*
 * Nonfatal error unrelated to a system call.
 * Print a message and return.
 */
void
err_msg(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(0, 0, fmt, ap);
    va_end(ap);
}


/*
 * Fatal error unrelated to a system call.
 * Print a message and terminate.
 */
void
err_quit(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(0, 0, fmt, ap);
    va_end(ap);
    exit(1);
}


/*
 * Print a message and return to caller.
 * Caller specifies "errnoflag".
 */
static void
err_doit(int errnoflag, int error, const char *fmt, va_list ap)
{
    char buf[MAXLINE];
    vsnprintf(buf, MAXLINE, fmt, ap);
    if (errnoflag)
        snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s",
                 strerror(error));
    strcat(buf, "\n");
    fflush(stdout); /* in case stdout and stderr are the same */
    fputs(buf, stderr);
    fflush(NULL); /* flushes all stdio output streams */
}

socketServer.h:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include "mysocket.h"

void read_data(int sockfd){
    ssize_t n;
    char buf[1024];

    int time = 0;
    while(1){
        fprintf(stdout, "block in read\n");
        if((n = readn(sockfd, buf,1024)) == 0){
            return;
        }
        time++;
        fprintf(stdout, "1K read for %d \n", time);
        usleep(10000);
    }
}

int main(int argc, char **argv){
    int listenfd, connfd;
    socklen_t clilen;
    struct sockaddr_in cliaddr, servaddr;
    // 创建 socket 套接字,bind 到对应地址和端口,并开始调用 listen 接口监听
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if(listenfd == -1){
        perror("socket");
        exit(1);
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(12345);

    /* bind 到本地地址,端口号为12345 */
    if(bind(listenfd, (const struct sockaddr *) &servaddr, sizeof(servaddr))){
        perror("bind");
        exit(1);
    }

    /* listen的backlog 为 1024 */
    if(listen(listenfd, 1024)){
        perror("listen");
        exit(1);
    }
    // 循环等待连接,通过 accept 获取实际的连接,并开始读取数据
    while(1){
        clilen = sizeof(cliaddr);
        connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
        if(connfd == -1){
            perror("accept");
            exit(1);
        }
        // 实际每次读取 1K 数据,之后休眠 1 秒,用来模拟服务器端处理时延
        read_data(connfd);
        close(connfd);
    }
}

socketClient.c:

#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include <arpa/inet.h>
#include "mysocket.h"

//# define MESSAGE_SIZE 10240000
# define MESSAGE_SIZE 1024000 // 改小这个参数,同时Server的睡眠时间加长,可以看到send into buffer很快打印出来了,而Server端还在打印,因为此时,发送的数据已经到发送端的发送缓冲区了,发送端send函数结束了
void send_data(FILE *fp, int sockfd)
{
    char * query;
    query = malloc(MESSAGE_SIZE+1);
    for(int i=0; i< MESSAGE_SIZE; i++){
        query[i] = 'a';
    }
    query[MESSAGE_SIZE] = '\0';

    const char *cp;
    cp = query;
    int remaining = strlen(query);
    //while循环这个例子中没用,一次就发完了
    while (remaining) {
        int n_written = send(sockfd, cp, remaining, 0);
        fprintf(stdout, "send into buffer %ld \n", n_written);
        if (n_written <= 0) {
            perror("send");
            return;
        }
        remaining -= n_written;
        printf("remaining: %d", remaining);
        cp += n_written;
    }

    return;
}

int main(int argc, char **argv){
    int sockfd;
    struct sockaddr_in servaddr;
    if(argc != 2){
        err_quit("usage: tcpclient <IPaddress>");
    }

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1){
        perror("socket");
    }
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(12345);
    inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    if(connect(sockfd, (const struct sockaddr *) &servaddr, sizeof(servaddr)) == -1){
        perror("connect");
    }
    send_data(stdin, sockfd);
    exit(0);

}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐