《TCP/IP网络编程》笔记4-基于TCP的服务器端客户端1

概述

第一节理解套接字已经完成了tcp server的实现,但是处理完一个client请求之后就退出了。本节进行一下扩展。

理解tcp和udp

下图为tcp/IP协议栈的四层协议:

当然OSI规定了7层协议,但对于我们编写网络通讯程序来说理解这四层协议足够了

四层协议

  • 链路层是物理链接的标准化,定义LAN,WAN等标准
  • IP层解决路径选择问题
  • TCP/UDP层建立在IP层基础之上,决定传输方式
  • 应用层是我们实现网络通讯时真正接触到的一层,前边的路径选择,数据确认等过程都被隐藏在套接字内部,我们只需要设计应用层协议即可。

    基于tcp的服务器端/客户端

    下图是服务器端和客户端的socket函数调用流程,阴影部分前边的章节介绍过,这里只介绍其他三个函数listen accept connect
    这里写图片描述
    只有服务端已经调用了listen,客户端才能发出连接请求。
    listen(sock,n) 第一参数就像门卫,也像分号台的一个护士,来安排请求连接的客户端。而第二个参数就是等候厅的大小。
    accept自动产生与客户端实际连接的套接字,用于实际的数据通讯,不同于listen分号太的护士。
    对于connect有一点说明,可以看到在server端我们通过bind函数指定了ip和端口号,而客户端确没有这么做。为什么呢?

    网络数据交换是必须要分配ip和端口的。其实对于客户端,在调用connect函数时由操作系统把本机ip和一个随机端口自动分配了。无需程序指定。

    迭代服务端/客户端的实现

    server代码如下:

// tcpserverwin.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment (lib,"ws2_32.lib") 

#define BUF_SZ 1024
int main(int argc, char* argv[])
{
    WSADATA wsaData;
    SOCKET hSocket,hClientSock;
    SOCKADDR_IN servAddr,clientAddr;
    int strlen,i;
    //char message[] = "hello client, I am server\n";
    char message[BUF_SZ];
    int szClientAddr;
    if(argc!=2){
        printf("usage : %s port\n",argv[0]);
        return 0;
    }
    if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){
        printf("WSAStartup  failed\n");
        return 0;
    }
    hSocket = socket(PF_INET,SOCK_STREAM,0);
    if(hSocket == INVALID_SOCKET){
        printf("socket error\n");
        return 0;
    }
    memset(&servAddr,0,sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(atoi(argv[1]));

    //int bind(hSocket,(SOCKADDR*)&servAddr,sizeof(servAddr));
    if(bind(hSocket,(SOCKADDR*)&servAddr,sizeof(servAddr)) == SOCKET_ERROR){
        printf("bind port [%d] error\n",atoi(argv[1]));
        return 0;
    }

    if(listen(hSocket,5) == SOCKET_ERROR){
        printf("listen error\n");
        return 0;
    }

    szClientAddr = sizeof(clientAddr);

    for (i=0;i<5;i++)
    {
        hClientSock = accept(hSocket,(SOCKADDR*)&clientAddr,&szClientAddr);
        if(hClientSock == INVALID_SOCKET){
            printf("accept error\n");
            continue;
        }
        else{
            printf("accept client:%d\n",i);
        }
        while((strlen=recv(hClientSock,message,BUF_SZ,0))!=0){
            send(hClientSock,message,strlen,0);
        }
        closesocket(hClientSock);
    }

    closesocket(hSocket);
    WSACleanup();
    return 0;
}

client代码如下:

// tcpclientwin.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment (lib,"ws2_32.lib") 
#define BUF_SZ 1024
int main(int argc, char* argv[])
{
    WSADATA wsaData;
    SOCKET hSocket;
    SOCKADDR_IN servAddr;
    char message[BUF_SZ];
    memset(message,0,sizeof(message));
    int slen;
    if(argc!=3){
        printf("usage : %s ip port\n",argv[0]);
        return 0;
    }
    if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){
        printf("WSAStartup  failed\n");
        return 0;
    }
    hSocket = socket(PF_INET,SOCK_STREAM,0);
    if(hSocket == INVALID_SOCKET){
        printf("socket error\n");
        return 0;
    }
    memset(&servAddr,0,sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = inet_addr(argv[1]);
    servAddr.sin_port = htons(atoi(argv[2]));

    if(connect(hSocket,(SOCKADDR*)&servAddr,sizeof(servAddr)) == SOCKET_ERROR){
        printf("connect error\n");
        return 0;
    }

    for (;;)
    {
        fgets(message,BUF_SZ,stdin);
        if(!strcmp(message,"q\n")){
            break;
        }
        char msg[] = "hello server";
        send(hSocket,msg,strlen(msg),0);
        slen = recv(hSocket,message,sizeof(message)-1,0);
        if (slen == -1)
        {
            printf("recv error\n");
        }
        printf("message from server:%s\n",message);
    }

    closesocket(hSocket);
    WSACleanup();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值