UDP中connet()的验证代码

Server:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char **argv)
{
    int sockfd;
    struct sockaddr_in servaddr, fromAddr;
    socklen_t fromAddrLen;
    char *addrBuf;

    sockfd = socket(PF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0){
        perror("SOCKET :");
        exit(1);
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);/* INADDR_ANY 指定IP地址为本地主机上任意IP地址 */
    servaddr.sin_port = htons(8888);             /* 端口为 8888 */

#if 1 
    /* 对于"服务器"来说,必须要要绑定一个客户端知道的端口号,客户端才能向该端口发送数据 */
   if( bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
        perror("BIND :");
        exit(1);
   }
#endif
    int n;
    char recvline[1024];
    memset(recvline, 0, sizeof(recvline));

    printf("wait receiving....\n");
    while(1){

        memset(&fromAddr, 0, sizeof(fromAddr));
        fromAddrLen = sizeof(fromAddr);

        /* 接收数据,所有到达本机的且端口号为8888的数据包都交由本进程处理
         * 对方的地址会保存在fromAddr结构体中 */
        if(recvfrom(sockfd, recvline, 1024, 0, (struct sockaddr *)&fromAddr, &fromAddrLen) < 0){
            perror("Error :");
            break;
        }
        addrBuf = inet_ntoa(fromAddr.sin_addr);
        printf("A client from %s:%d\n", addrBuf, ntohs(fromAddr.sin_port));
        printf("%s\n", recvline);
#if 1
        strcpy(recvline, "ok");

        if(sendto(sockfd, recvline, strlen(recvline), 0, (struct sockaddr *)&fromAddr, sizeof(fromAddr)) <= 0){
            perror("Sendto : ");
        }
#endif
    }

    printf("servce will exiting...\n");

    close(sockfd);
}

Client:

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

int main(int argc, char *argv[])
{
    int sock, recvLen;
    struct sockaddr_in toAddr, bindAddr, testAddr;
    struct sockaddr_in fromAddr;
    unsigned int fromLen;
    char recvBuffer[128];
    char sendBuffer[] = "hello this is udp broadcast";

    sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
    if(sock < 0){
        fprintf(stderr,"socket():%s\n", strerror(errno));
        exit(1);
    }

    memset(&toAddr,0,sizeof(toAddr));
    toAddr.sin_family = AF_INET;
    toAddr.sin_addr.s_addr = inet_addr("192.168.1.20");
    toAddr.sin_port = htons(8888);

    memset(&bindAddr, 0, sizeof(bindAddr));
    bindAddr.sin_family = AF_INET;
    bindAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    bindAddr.sin_port = htons(7777);

    memset(&testAddr, 0, sizeof(testAddr));
    testAddr.sin_family = AF_INET;
    testAddr.sin_addr.s_addr = inet_addr("192.168.1.118");
    testAddr.sin_port = htons(9999);

    int opt = 1;
    if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt)) != 0){
        perror("setockopt() : \n");
        close(sock);
        exit(1);
    }

#if 1
    /* 要"被动"的接收数据,必须绑定一个客户端知道的地址和端口,以便客户端主动向该地址发送数据 
        * 若进程不绑定地址和端口,则由内核自动为其选择一个合适的地址和端口,这样也能监听,但是客户端不
     * 知道地址和端口,很不方便连接 */
    if(bind(sock, (struct sockaddr *)&bindAddr, sizeof(bindAddr)) != 0){
        perror("Bind : ");
        close(sock);
        exit(1);
    }
#endif

#if 1
    /* 若想以后仅仅与一个主机通讯,则可以调用connect()指定目的地址,这样就可以调用recv(),send()
     * 这样发送的数据会到达toAddr, 进程也只能接收到toAddr发送的数据包 ,调用connect()之后,对于错误状态可知的情况,
     * 内核会返回到进程 */
    if(connect(sock, (struct sockaddr *)&toAddr, sizeof(toAddr)) != 0){
        perror("Connect : ");
        close(sock);
        exit(1);
    }
#endif

#if 0
    /* 调用connect()之后,进程可以使用send()来代替sendto() */
    if(send(sock, sendBuffer, strlen(sendBuffer), 0) <= 0){
        perror("Send : ");
        close(sock);
        exit(1);
    }else{
        printf("sent done!\n");
    }
#endif

#if 1
    /* 当然调用了connect()之后,进程仍然可以使用sendto(),但是第5、6个参数要么NULL,0,要么只能和原来的地址相同,
     * 否则会调用失败 */
    if(sendto(sock, sendBuffer,strlen(sendBuffer),0,(struct sockaddr*)&toAddr,sizeof(toAddr)) != strlen(sendBuffer)){
        fprintf(stderr,"sendto():%s\n", strerror(errno));
        close(sock);
        exit(1);
    }else{
        printf("sent done!\n");
    }
#endif  

#if 0

    /* 调用connect()之后,进程仍然可以使用recvfrom(),但此时只能收到connect()指定的地址的发来的数据包 
     * 对于已知的错误,内核会告知进程,例如进程调用recvfrom()接收本机回环口127.0.0.1:8888的数据,若127.0.0.1:8888
     * 有进程在监听,那么recvfrom()会阻塞,直到收到数据,若127.0.0.1并没有进程在监听,那么recvfrom()会直接返回,并且
     * errno错误号会表明: "connection refused"。
     * 若调用recvfrom接收网络上另一个地址发来的数据,即使该地址上并没有进程在工作,而内核也不知道
     * 是否该主机上的某某端口是否打开,因为内核并不为UDP向该主机的端口发送任何探测报文(TCP三次握手完成,内核当然知道对方的状态),
     * 那么本机的进程也不会被告知错误 (可以写个程序验证)*/
    fromLen = sizeof(fromAddr);
    memset(recvBuffer, 0, sizeof(recvBuffer));
    if((recvLen = recvfrom(sock,recvBuffer,128,0,(struct sockaddr*)&fromAddr,&fromLen))<0){
        fprintf(stderr,"recvfrom():%s\n", strerror(errno));
        close(sock);
        exit(1);
    }

    printf("recvfrom() result len : %d, content %s\n", recvLen, recvBuffer);

#endif

#if 1
    /* 调用了connect()之后,可以使用recv()来代替recvfrom() */
    printf("receiving...\n");
    if((recvLen = recv(sock, recvBuffer, 128, 0)) < 0){
        perror("recv() : ");
        close(sock);
        exit(1);
    }

    printf("recv() result len : %d, content %s\n", recvLen, recvBuffer);
#endif

    close(sock);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值