网络编程:使用tcp协议实现服务器与客户端交互

服务器

**************************************************************************************************************

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

#define PTOR 6666
#define IP      "192.168.31.162"

#define ERR_MSG(msg)  do{
    fprintf(stderr,"__%d__n",__LINE__);
    perror(msg);
}while(0)

int main(int argc, const char *argv[])
{
    //1、创建流式套接字,返回值为文件描述符
    int sfd=socket(AF_INET,SOCK_STREAM,0);
    if(sfd<0)
    {
        ERR_MSG("socket");
        return -1;
    }

    //如果不加这段代码,则服务器异常退出后,会导致端口号在30s~3min内释放不出来
    //当程序结束后,想要让其他进程能够快速复用端口号,就可以使用下面的代码
    //允许端口快速被重用
    int reuse = 1;
    if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse ,sizeof(reuse)) < 0)
    {   
        ERR_MSG("setsockopt");
        return -1;                                                                                    
    }   
    printf("允许端口快速重用n");

    //2、填充地址信息结构体,真实的地址信息结构体根据地址族制定
    struct sockaddr_in sin;
    sin.sin_family =AF_INET;//必须填AF_INET;
    sin.sin_port   =htons(PTOR);//网络字节序,端口号是2字节,所以用htons将主机字节序转为网络字节序
    sin.sin_addr.s_addr   =inet_addr(IP);//本机IP
    //printf("%d:%d_,%#xn",__LINE__,htons(PTOR),inet_addr(IP));
    //3、将地址信息结构体绑定到套接字上
    if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))<0)
    {
        ERR_MSG("bind");
        return -1;
    }
    //4、将套接字设置为被动监听状态
    if(listen(sfd,128)<0)
    {
        ERR_MSG("listen");
        return -1;
    }
    printf("服务器设置被动监听设置成功n");

    struct sockaddr_in cin;
    socklen_t  cinlen=sizeof(cin);
    //5、accept从队头获取一个客户端信息
    int newfd = accept(sfd,(struct sockaddr *)&cin,&cinlen);
    if(newfd<0)
    {
        ERR_MSG("accept");
        return -1;
    }
    printf("[%s:%d] newfd = %d 连接成功n",
            inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);

    //6、数据传输
    char buf[32]="";
    ssize_t res=0;
    while(1)
    {
        //接收
        bzero(buf,sizeof(buf));

         res=recv(newfd,buf,sizeof(buf),0);
        if(res<0)
        {
            ERR_MSG("recv");
            return -1;
        }
        else if(0==res)
        {
            printf("newfd=%d 客户端关闭n",newfd);
            break;
        }
        printf("res:%ld,newfd:%d,res:%sn",res,newfd,buf);

        //发送
        //将发送一个数据到用户IP
        printf("服务器发送–>n");
        fgets(buf,sizeof(buf),stdin);
        buf[sizeof(buf)-1]=0;
        if(send(newfd,buf,sizeof(buf),0)<0)
        {
            ERR_MSG("send");
            return -1;
        }
        bzero(buf,sizeof(buf));

        printf("send successn");
    }
    close(newfd);
    close(sfd);
    return 0;
}
**************************************************************************************************************

客户端

**************************************************************************************************************

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

#define ser_PTOR 6666
#define ser_IP      "192.168.31.162"

#define ERR_MSG(msg)  do{
    fprintf(stderr,"__%d__n",__LINE__);
    perror(msg);
}while(0)

int main(int argc, const char *argv[])
{
    //1、创建流式套接字,返回值为文件描述符
    int sfd=socket(AF_INET,SOCK_STREAM,0);
    if(sfd<0)
    {
        ERR_MSG("socket");
        return -1;
    }

    //绑定客户端自身IP和端口,到对应的套接字上;——非必要绑定
    //不绑定程序运行后操作系统会自动分配一个在49152—65535之间的端口号给套接字

    //填充地址信息结构体,真实地址信息结构体根据地址族来制定
    //struct sockaddr_in 

    //2、填充服务器的地址信息结构体,因为connect函数中要通过地址信息结构体来链接服务器
    struct sockaddr_in sin;
    sin.sin_family =AF_INET;//必须填AF_INET;
    sin.sin_port   =htons(ser_PTOR);//服务器绑定的端口
    sin.sin_addr.s_addr   =inet_addr(ser_IP);//服务器绑定的IP
    //注意,切换网络环境后IP是会发生改变的

    //3、连接服务器
    if(connect(sfd,(struct sockaddr *)&sin,sizeof(sin))<0)
    {
        ERR_MSG("connect");
        return -1;
    }
    printf("connect successn");
    struct sockaddr_in cin;
    socklen_t  cinlen=sizeof(cin);
    //6、数据传输
    char buf[32]="";
    ssize_t res=0;
    while(1)
    {
        //发送
        //将获取到的数据拼接后发送回去
        printf("请输入–>n");
        fgets(buf,sizeof(buf),stdin);
        buf[sizeof(buf)-1]=0;
        if(send(sfd,buf,sizeof(buf),0)<0)
        {
            ERR_MSG("send");
            return -1;
        }
        bzero(buf,sizeof(buf));
        printf("send successn");

        //接收
        bzero(buf,sizeof(buf));
        res=recv(sfd,buf,sizeof(buf),0);
        if(res<0)
        {
            ERR_MSG("recv");
            return -1;
        }
        else if(0==res)
        {
            printf("sfd=%d 客户端关闭n",sfd);
            break;
        }
        printf("res:%ld,sfd:%d,res:%sn",res,sfd,buf);
    }
    close(sfd);
    return 0;
}
 

Published by

风君子

独自遨游何稽首 揭天掀地慰生平