网络编程,socket编程,TCP

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hello_world12138/article/details/48710919
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">关于网络编程,socket编程,TCP,客户端,服务器C/S架构编程思路</span>


学习这个我感觉是看着困难,理解了以后,原理还是能够 接受的,有什么不对的地方还请大牛们指正。

下面给出的知识服务器和客户端能够互发信息,在此基础上可以在客户端和服务器添加线程,这样就是即时通讯软件项目的前身了,服务器通过每个客户端的fd,确认是哪个客户端,从而准确的发送和接收消息,最终能够做到客户端和客户端之间互发信息。



头文件:

#ifndef __TCP_NET__SOCKET__H
#define __TCP_NET__SOCKET__H
#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>
#include <unistd.h>
#include <signal.h>

#endif




客户端:
客户端负责的内容较少,主要是建立套接字,然后发送连接请求,如果连接成功了,那么下面的就可以发送和接收了。
1.首先,执行可执行文件时,需要给出相应的ip用于连接。
2.接着,申请一个流式套接字,得到描述符sfd
3.把需要连接的服务器的网络的ip地址族,端口号,ip都和该套接字建立关联关系
4.接着就向服务器发送数据

#include "5.tcp_net_socket.h"

//公用的端口号
#define PORTNUMBER 2333


//连接函数
int tcp_connect(const char *ip)
{
    //向系统注册新的socket用于通信,sfd是该socket的fd
    int sfd = socket(AF_INET,SOCK_STREAM,0);
    if(sfd == -1)
    {
        perror("build a new socket failed!\n");
	exit(-1);
    }

    //用于将新的socket的sfd,连接至一个网络地址,也就是服务器对应的网络地址,就是连接的过程
    /*以下为几个结构体,定义的结构体,sockaddr_in最终会被强制转换为sockaddr
    struct sockaddr
    {
        unsigned short int sa_family;
	char sa_data[14];
    };

    struct socketaddr_in
    {
        unsigned short int sin_family;
	uint16_t sin_port;
	struct in_addr sin_addr;
	unsigned char sin_zero[8];
    };

    struct in_addr
    {
        uint32_t s_addr;
    };
    */
    //定义的serveraddr将用于连接网络
    struct sockaddr_in serveraddr;
    memset(&serveraddr,0,sizeof(struct sockaddr));
    //地址族是ipv4
    serveraddr.sin_family = AF_INET;
    //设置进程的端口号,用于和ip地址配合,进而唯一确定一个进程,进行通信
    serveraddr.sin_port = htons(PORTNUMBER);
    //将输入的ip地址转换为网络字节序列,例如192.168.1.1 转化为1100 0000.1010 1000.0000 0001.0000 0001
    serveraddr.sin_addr.s_addr = inet_addr(ip);

    //将sfd连接至指定的服务器网络地址serveraddr
    if(connect(sfd,(struct sockaddr *)&serveraddr,sizeof(struct sockaddr)) == -1)
    {
        perror("connect error\n");
	close(sfd);
	exit(-1);
    }
    return sfd;
}



int main(int argc,char *argv[])
{
    //客户端开启需要三个参数:命令,ip
    if(argc < 2)
    {
        printf("user:./clienttcp ip\n");
	exit(-1);
    }

    //自定义函数 tcp_connect,将ip作为参数传入,函数返回新建的套接字的fd
    int sfd = tcp_connect(argv[1]);

    //尝试向服务器发送一些数据,检测是否连接成功
    char buf[512] = {0};
    //调用函数send,进行发送,参数为,本套接字fd,内容,内容长度,置为0的flag
    send(sfd,"hello!SB",9,0);
    //从服务器接收数据
    recv(sfd,buf,sizeof(buf),0);
    //显示接收到的数据
    puts(buf);
    //是不是该关闭,有待尝试
    close(sfd);
}






服务器:
服务器负责的内容较客户端多,主要是,建立新的套接字,然后对套接字进行绑定,再监听客户端的连接请求,然后接受请求,算连接成功了
1.首先,执行可执行文件时,同样需要ip地址。
2.接着初始化,申请套接字,将这个套接字和该网络进行关联,也就是绑定。
3.接着对客户端的请求进行监听。
4.然后定义一个新的结构体,用于保存请求的客户端的信息,并申请新的socket,产生新的fd,即new_fd

5.连接成功的话,就可以正常的发送和接收信息了。



#include "5.tcp_net_socket.h"

#define PORTNUMBER 2333


void signalhandler(void);
int tcp_init(const char *ip,int port);
int tcp_accept(int sfd);


//用于信号处理,让服务器在按下ctrl + c 或者 ctrl + \时,不会退出
void signalhandler(void)
{
    sigset_t sigSet;
    sigemptyset(&sigSet);
    sigaddset(&sigSet,SIGINT);
    sigaddset(&sigSet,SIGQUIT);
    sigprocmask(SIG_BLOCK,&sigSet,NULL);
}


//用于申请新的套接字,然后綁定相应网络,再对客户端的请求监听
int tcp_init(const char *ip,int port)
{
    //服务端申请新的套接字
    int sfd = socket(AF_INET,SOCK_STREAM,0);
    if(sfd == -1)
    {
        perror("build new socket failed!\n");
	exit(-1);
    }

    //和客户端的connect类似,将套接字也与该网络地址联系起来,也就是綁定
    struct sockaddr_in serveraddr;
    memset(&serveraddr,0,sizeof(struct sockaddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(port);
    serveraddr.sin_addr.s_addr = inet_addr(ip);

    if(bind(sfd,(struct sockaddr *)&serveraddr,sizeof(struct sockaddr)) == -1)
    {
        perror("bind failed!\n");
	close(sfd);
	exit(-1);
    }

    //对客户端的连接进行监听,是否有申请连接?
    if(listen(sfd,10) == -1)
    {
        perror("listen failed!\n");
	close(sfd);
	exit(-1);
    }

    return sfd;
}


int tcp_accept(int sfd)
{
    //定义一个结构体,用于保存请求连接的客户端的ip 和 port
    struct sockaddr_in clientaddr;
    memset(&clientaddr,0,sizeof(struct sockaddr));
    int addrlen = sizeof(struct sockaddr);
    //服务器接受了客户端的请求,并且连接成功后,会创建新的套接字,fd为new_fd,
    //这个new_fd将会被用来服务器向客户端的通信
    int new_fd = accept(sfd,(struct sockaddr *)&clientaddr,&addrlen);

    if(new_fd == -1)
    {
        perror("accept failed!\n");
	close(sfd);
	exit(-1);
    }

    printf("%s  %d success connect....\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));

    return new_fd;
}



int main(int argc, char *argv[])
{
    //服务器开启的时候也需要设置ip
    if(argc < 2)
    {
        printf("usage:./servertop, ip\n");
	exit(-1);
    }

    //用于信号处理,让服务器在按下ctrl + c 或者 ctrl + \时,不会退出
    signalhandler();

    //用于初始化套接字,返回该套接字的fd
    int sfd = tcp_init(argv[1],PORTNUMBER);

    //开始死循环,用于挂起服务器,实时接收客户端连接请求
    while(1)
    {
        int cfd = tcp_accept(sfd);
	char buf[512] = {0};

        //接收客户端发送来的信息,在buf中保存
	if(recv(cfd,buf,sizeof(buf),0) == -1)
	{
	    perror("recv failed\n");
	    close(cfd);
	    close(sfd);
	    exit(-1);
	}

	puts(buf);

        //从服务器向客户端发送数据,为客户端之间互发数据做准备
	if(send(cfd,"hello, i'm server",17,0) == -1)
	{
	    perror("send failed !\n");
	    close(cfd);
	    close(sfd);
	    exit(-1);
	}
	close(cfd);
    }
    close(sfd);
    return 0;


}





猜你喜欢

转载自blog.csdn.net/hello_world12138/article/details/48710919