Linux下套接字详解(四)----简单的TCP套接字应用(迭代型)

来源:互联网 发布:淘宝同款排除王工具 编辑:程序博客网 时间:2024/06/05 19:52

TCP编程流程说明

(1)SERVER 服务器端编程流程

TCP服务器端编程流程如下:

① 创建套接字socket; 
② 绑定套接字bind; 
③ 设置套接字为监听模式,进入被动接受连接状态listen; 
④ 接受请求,建立连接accpet; 
⑤ 读写数据read/write; 
⑥ 终止连接close。

(2) CLIENT客户端编程流程

TCP客户端编程流程如下:

① 创建套接字socket; 
② 与远程服务器建立连接connect; 
③ 读写数据read/write; 
④ 终止连接close。

异常机制


3) TCP服务器三种异常情况

TCP服务器有三种异常情况,分别为服务器主机崩溃服务器主机崩溃后重启服务器主机关机

服务器主机崩溃

在服务器主机崩溃的情况下,已有的TCP网络连接上发不出任何东西。 
此时客户端发出数据后,会一直阻塞在套接字的读取响应。但是由于服务器主机已崩溃,TCP客户端会持续重传数据分节,试图从服务器接收一个ACK[一般重传12次(源自Berkeley的实现)]后,客户TCP最终选择放弃,返回给应用经常一个ETIMEDOUT错误;或者是因为中间路由器判定服务器主机不可达,则返回一个目的地不可达的ICMP消息响应,其错误代码为EHOSTUNREACH或ENETUNREACH。 
简单来说,客户端会一直阻塞与read调用,然后一直重传,直到最后超时,客户最终会发现服务器主机已崩溃或主机不可达,然后返回一个状态码,但是这个过程可能是很长就的,解决的方法就是自己写一个read函数然后设置超时,或者加一个SO_KEEPALIVE选项,也可以通过设置套接字选项可以更改TCP持续重传等待的超时时间。

服务器主机崩溃后重启

在服务器主机崩溃后重启的情况下,如果客户在主机崩溃重启前不主动发送数据,那么客户是不会知道服务器已崩溃。

在服务器重启后,客户向服务器发送一个数据分节;由于服务器重启后丢失了以前的连接信息(尽管在服务端口上有进程监听,但连接套接字所在的端口无进程等待),因此导致服务器主机的TCP响应RST;而客户由于之前未收到服务器的响应数据,页阻塞于read调用,当客户端收到这个RST之后便返回错误ECONNRESET。

如果客户对服务器的崩溃情况很关心,即使客户不主动发送数据也这样,这需要进行相关设置(如设置套接口选项SO_KEEPALIVE或某些客户/服务器心跳函数)。

服务器主机关机 
这里一般指的是正常关机,因为Unix系统关机时,会发送SIGTERM和SIGKILL信号,SIGTREM可能忽略,但是SIGKILL信号不能忽略,于是服务器将由SIGKILL终止, 
当服务器主机关机的情况下,由于init进程给所有运行的进程发信号SIGTERM,这时服务器程序可以捕获该信号,并在信号处理程序中正常关闭网络连接。如果服务器程序忽略了SIGTERM信号,则init进程会等待一段固定的时间(通常是5s~20s),然后给所有还在运行的程序发信号SIGKILL。服务器将由信号SIGKILL终止,其终止时,所有打开的描述字被关闭,这导致向客户发送FIN分节,客户收到FIN分节后,能推断出服务器将终止服务。

简单的TCP套接字应用程序


我们下面将实现一个迭代类型的简单TCP服务器与客户端,实现客户端从服务器上传/下载文件(我们的程序中主要是上传)。

TCP服务器

/**********************************************************    > File Name: server.c    > Author: GatieMe    > Mail: gatieme@163.com    > Created Time: 2015年04月11日 星期六 16时22分10秒 *********************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/wait.h>#include <arpa/inet.h>#include <unistd.h>#include <signal.h>#define TCP_SERVER_PORT     6666    /*  服务器的端口  */#define BUFFER_SIZE         4096#define IP_SIZE             20#define MAX_FILENAME_SIZE   256#define LISTEN_QUEUE        20/* 服务器接收从客户端传送来的文件  */voidTcpServerPullFile(            int         connfd,                     /*  服务器与客户端通讯的套接字文件  */            struct      sockaddr_in clientAddr,     /*  与之通信的客户端的信息  */            char        *fileServerRoot)            /*  上传文件的存储路径  */{    char    buffer[BUFFER_SIZE];    char    filename[MAX_FILENAME_SIZE];    char    fileServerPath[MAX_FILENAME_SIZE]/* = fileServerRoot*/;    // 定义文件流    FILE    *stream;    int     count;              /*  发送文件名的字节数目  */    int     dataLength;         /*  接收到的数据大小  */    int     writeLength;        /* 实际写入的数据大小  */    int     flag = 0;    bzero(buffer, BUFFER_SIZE);    /*     *  向客户端提示输入文件路径提示...     *     * strcpy(buffer, "请输入要传输的文件的完整路径:");    strcat(buffer, "\n");    send(new_server_socket, buffer, BUFFER_SIZE, 0);    bzero(buffer, BUFFER_SIZE);    */    /*  首先获取客户端发送过来的文件名  */    count = recv(connfd, buffer, BUFFER_SIZE, 0);    if(count < 0)    {        perror("获取文件名失败...\n");        exit(1);    }    else    {        strncpy(filename, buffer, strlen(buffer) > MAX_FILENAME_SIZE ? MAX_FILENAME_SIZE : strlen(buffer));        strcpy(fileServerPath, fileServerRoot);        strcat(fileServerPath, filename);        printf("\n获取客户端发送过来的文件名成功...\n");        printf("文件名[%s]\n", filename);        printf("文件存储路径[%s]\n\n", fileServerPath);    }    //  服务器接受数据, 首先打开一个文件流    if((stream = fopen(fileServerPath, "w")) == NULL)    {        perror("file open error...\n");        exit(1);    }    else    {        bzero(buffer,BUFFER_SIZE);    }    printf("正在接收来自%s的文件....\n",inet_ntoa(clientAddr.sin_addr));    dataLength = 0;    /*  先将数据接受到缓冲区buffer中,再写入到新建的文件中  */    while((dataLength = recv(connfd, buffer, BUFFER_SIZE, 0)) > 0)    {        flag++;        if(flag == 1)        {            printf("正在接收来自%s的文件....\n", inet_ntoa(clientAddr.sin_addr));        }        if(dataLength < 0)        {            printf("接收错误i\n");            exit(1);        }        /*  向文件中写入数据  */        writeLength = fwrite(buffer, sizeof(char), dataLength, stream);        if(writeLength != dataLength)        {             printf("file write failed\n");             exit(1);        }        bzero(buffer,BUFFER_SIZE);    }    if(flag > 0)    {        printf("%s的文件传送完毕\n", inet_ntoa(clientAddr.sin_addr));    }    if(flag==0)    {        printf("%s的文件传输失败\n", inet_ntoa(clientAddr.sin_addr));    }    fclose(stream);    //rename("data",inet_ntoa(clientAddr.sin_addr));}/*  服务器将文件发送到客户端 * *  当用户选择了下载文件后,服务器将执行此操作 * *  */void TcpServerPushFile(                    int         connfd,                  /*  服务器与客户端通讯的套接字文件  */                    struct      sockaddr_in clientAddr,  /*  与之通信的客户端的信息  */                    char        *filePath)              /*  带发送至客户端的文件路径  */{    //send file imformation    char    buff[BUFFER_SIZE];    char    filename[MAX_FILENAME_SIZE];    int     count;    FILE    *stream;    /* 先将文件名发送给客户端     * 2015-4-13 21:38 Modify     * 发送文件名时只需要发送filePath最后的文件名filename就可以了     * */    bzero(buff, BUFFER_SIZE);    strcpy(filename, strrchr(filePath, '/') + 1);    strncpy(buff, filename, strlen(filename) > MAX_FILENAME_SIZE ? MAX_FILENAME_SIZE : strlen(filename));    count = send(connfd, buff, BUFFER_SIZE, 0);    printf("服务器待发送的文件名[%s]..\n", filename);    if(count < 0)    {        perror("Send file information");        exit(1);    }    /*  服务器开始读取并且发送文件 : */    if((stream = fopen(filePath, "rb")) == NULL)    {        printf("File :%s not found!\n",filePath);    }    printf("服务器打开文件成功...\n");    printf("正在向客户端发送文件...\n");    bzero(buff, BUFFER_SIZE);    int fileBlockLength = 0;    while((fileBlockLength = fread(buff, sizeof(char), BUFFER_SIZE, stream)) > 0)    {        printf("读取了:%d个数据...\n",fileBlockLength);        if(send(connfd, buff, fileBlockLength, 0) < 0)        {            perror("Send file error...\n");            perror("向客户端发送文件失败...\n");            exit(1);        }        bzero(buff,BUFFER_SIZE);    }    fclose(stream);    printf("服务器发送文件成功\n");}extern int errno;int main(int argc, char *argv[]){    /**********************************************************     *     *  创建并初始化服务器套接字     *     **********************************************************/    struct sockaddr_in      serverAddr;    int                     socketFd;    bzero(&serverAddr, sizeof(serverAddr));     /*  全部置零  */    /* 设置地址相关的属性 */    serverAddr.sin_family         =   AF_INET;    serverAddr.sin_addr.s_addr    =   htons(INADDR_ANY);    serverAddr.sin_port           =   htons(TCP_SERVER_PORT);    /*  创建套接字  */    socketFd = socket(AF_INET, SOCK_STREAM, 0);    if(socketFd < 0)    {        perror("socket create error\n");        exit(-1);    }    else    {        printf("socket create success...\n");        printf("创建套接字成功[errno = %d]...\n", errno);    }    /*  绑定端口  */    if(bind(socketFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) > 0)    {        perror("bind error\n");        exit(1);    }    else    {        printf("server bind port %d success...\n", TCP_SERVER_PORT);        printf("服务器绑定端口%d成功...\n", TCP_SERVER_PORT);    }    /*  开始监听绑定的端口  */    if(listen(socketFd, LISTEN_QUEUE))    {        printf("Server listen error[errno = %d]...\n", errno);        exit(-1);    }    else    {        printf("Server listen success...\n");        printf("服务器开始监听...\n");    }    struct sockaddr_in  clientAddr;    socklen_t           length = sizeof(clientAddr);    int                 connFd;    while( 1 )    {        /* accept返回一个新的套接字与客户端进行通信  */        connFd = accept(socketFd, (struct sockaddr*)&clientAddr, &length);        if(connFd == -1)        {            printf("accept error[%d]...\n", errno);            continue;        }        else        {            printf("获取到从客户端%s的连接...\n", inet_ntoa(clientAddr.sin_addr));            ////////////////////////////////////////////////////////////////////////            //            //  这里填写服务器的处理代码            //            ////////////////////////////////////////////////////////////////////////            TcpServerPullFile(connFd, clientAddr, "./sdata/"); /*  将客户端发送来的文件存储在./sdata目录下  */            close(connFd);        }    }                //        sleep(10);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283

TCP客户端


/**********************************************************    > File Name: client.c    > Author: GatieMe    > Mail: gatieme@163.com    > Created Time: 2015年04月11日 星期六 12时05分02秒 *********************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/wait.h>#include <arpa/inet.h>#include <unistd.h>#include <signal.h>#define TCP_SERVER_PORT     6666#define MAX_FILENAME_SIZE   256#define IP_SIZE             20#define BUFFER_SIZE         4096/* 客户端将文件上传到服务器上 */void TcpClientPushFile(int socketFd, char *filePath){    FILE    *stream;    char    buffer[BUFFER_SIZE];    char    filename[MAX_FILENAME_SIZE];    int     count = 0;    bzero(buffer, BUFFER_SIZE);    strcpy(filename, strrchr(filePath, '/') + 1);    strncpy(buffer, filename, strlen(filename) > MAX_FILENAME_SIZE ? MAX_FILENAME_SIZE : strlen(filename));    count = send(socketFd, buffer, BUFFER_SIZE, 0);    printf("客户端待上传待文件名[%s]..\n", filename);    if(count < 0)    {        perror("Send file information");        exit(1);    }    /*  打开文件流  */    if((stream = fopen(filePath, "r")) == NULL)    {        printf("Can't open the file [%s]\n", filePath);        exit(1);    }    else    {        printf("客户端打开文件成功\n");    }    printf("正在向服务器传上传文件...\n");    count = 0;    /*  清空缓冲区  */    bzero(buffer, BUFFER_SIZE);    /*  不断读取并发送数据  */    while((count = fread(buffer, 1, BUFFER_SIZE, stream)) > 0)    {        // printf("count =%d\n", count);        if(send(socketFd, buffer, count, 0) < 0)        {            printf("send file error...\n");            break;        }        bzero(buffer, BUFFER_SIZE);  /*  再次将缓冲区清空  */    }    printf("向服务器发送文件成功...\n");    /* 传送完毕后, 关闭文件流  */    if(fclose(stream))    {        printf("file close error\n");        exit(1);    }    else    {        printf("关闭文件流成功...\n");    }    /*  关闭与服务器通讯的套接字  */    close(socketFd);}/* 从服务器上下载文件  */void TcpClientPullFile(int socketFd, char *filePath){    char    buff[BUFFER_SIZE];    char    filename[MAX_FILENAME_SIZE];    int     count, writeLength, dataLength;    FILE    *stream;    bzero(buff,BUFFER_SIZE);    /*  首先获取服务器发送过来的文件名  */    count = recv(socketFd, buff, BUFFER_SIZE, 0);    if(count < 0)    {        perror("获取文件名失败...\n");        exit(1);    }    strncpy(filename, buff, strlen(buff) > MAX_FILENAME_SIZE ? MAX_FILENAME_SIZE : strlen(buff));    /*  开始接收文件  */    printf("Preparing download file : %s", filename);    /*  打开文件流  */    if((stream = fopen(filename, "wb+")) == NULL)    {        perror("create file %s error...\n");        perror("创建文件失败...\n");        exit(1);    }    bzero(buff, BUFFER_SIZE);          /*  清空缓冲区  */    dataLength = 0;    while((dataLength = recv(socketFd, buff, BUFFER_SIZE, 0)) != 0)    {        if(dataLength < 0)  /* 如果接收文件失败  */        {            perror("download error...\n");            perror("下载文件失败...\n");            exit(1);        }        /*  将接收到的文件数据写入文件中  */        writeLength = fwrite(buff, sizeof(char), dataLength, stream);        if(writeLength < dataLength)   /*  如果写入的数据比实际接收到的数据少  */        {            perror("file write error...\n");            perror("写入文件失败...\n");            exit(1);        }        bzero(buff, BUFFER_SIZE);               /* 清空缓冲区  */    }    printf("下载来自服务器%s的文件成功\n", filename);    printf("Receieved file:%s finished!\n", filename);    fclose(stream);             /*  关闭文件流 */}int main(int argc, char *argv[]){    char                serverIp[IP_SIZE];             /*  服务器的IP地址       */    if(argc >= 2)                       /*  参数过多的时候,提示用户  */    {        printf("You have given to much parameters...\n");        printf("Yous should give the IP address after %s\n without any other parametes...\n", (char *)argv[0]);    }    else if(argc == 1)                  /*  只有一个参数,则默认使用localhost(127.0.0.1)  */    {        strcpy(serverIp, "127.0.0.1");    }    else    {        strcpy(serverIp, argv[1]);    }    /**********************************************************     *     *  创建并初始化套接字     *     **********************************************************/    struct sockaddr_in  serverAddr;          /*  服务器的套接字信息   */    int                 socketFd;                      /*  客户端的套接字信息   */    bzero(&serverAddr, sizeof(serverAddr));             /*  全部置零               */    serverAddr.sin_family       =   AF_INET;                      /*  internet协议族         */    serverAddr.sin_addr.s_addr  =   inet_addr(serverIp);        /*  设置所连接服务器的IP   */    serverAddr.sin_port         =   htons(TCP_SERVER_PORT);       /*  设置连接的服务器端口   */    /*  开始创建套接字                        */    /*  SOCK_STREAM 面向连接的套接字,即TCP   */    socketFd                    =   socket(AF_INET, SOCK_STREAM, 0);    if(socketFd < 0)    {        printf("socket error\n");        exit(-1);    }    /*  尝试连接服务器  */    if(connect(socketFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0)    {        printf("Can Not Connect To %s\n", serverIp);        exit(1);    }    else    {        printf("connect to the server %s SUCCESS...\n", serverIp);        printf("连接服务器成功...\n");    }    /**********************************************************     *     *  下面进行正常的套接字通信     *     **********************************************************/    // 上传文件到服务器    TcpClientPushFile(socketFd, "./cdata/push");    close(socketFd);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231

由于TCP和UDP在实现流程上有很多异曲同工之处,因此我们后面的拓展优化将主要针对TCP套接字程序,我们在下一篇开始UDP的套接字编程详解,理解了TCP不同的实现思想之后稍加修改即可。。。。

运行情况

TcpServer服务器 
TcpServer客户端

0 0