Socket sends and receives data

Let's try the socket to send and receive data.
There are three files in total: mysocket.h, socketServer.c, socketClient.c
Process:
1. Prepare these three files and put them in a directory
2. Execute gcc socketServer.c -o server.out
3. Execute gcc socketClient.c -o client.out
4. Execute in a terminal window: ./server.out, you can see that the current process is in a waiting state5 .Open another terminal window and execute: ./client.out
1
6. Observe the output of the two windows The
following are the source codes of the three files. Don’t worry about the red flag in the IDE, just follow the above process to execute.

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);

}

Guess you like

Origin blog.csdn.net/w907645377/article/details/123453377