您的位置:首页 > 理论基础 > 计算机网络

TCP服务器、客户端的简单实现

2017-08-06 23:24 507 查看
1.  IP地址(IPV4   IPV6) 

 以一个32位的整形表示:172.166.111.110  -》点分10进程   

   地址     255.255.255.255    

表示为     FF   FF   FF  FF   ->二进程  

2.IP地址分类

A类地址:0.0.0.0    --   127.255.255.255                  
       网络号 +  主机号  网络号高(0-7)  主机号低(8—31)

B类地址:128.0.0.0  --   191.255.255.255                        网络号高(0-15) 主机号低(16-31)

C类地址: 192.0.0.0  --   223.255.255.255                        网络号高(0-23) 主机号低(24-31)

D类地址:224.0.0.0  --   239.255.255.255                        用来做组播网络

E类地址:240.0.0.0  --   255.255.255.255                        用来做广播网络 

说明:网络号  -》识别是那个网络  

            主机号  -》识别是那一台PC

192.168.7.6    ---》  C类地址      网络通信时必须要地址段相同

192.168.6.6    ---》  C类地址

3.端口号    -》识别主机中的哪一个进程

IP地址:识别网络中的那一套主机,端口号就是用来识别,当前主机中的哪一个进程

端口号的取值范围:1-65535    

在使用端口号时要注意:一般使用1000以后的端口号,因为1000以前的端口号,一般被系统进程占用着

-----------------------------------------------------------------------------------------------------

传输层协议:

TCP协议     UDP协议

TCP协议可靠传输协议:一般用于文件传输,与控制命令传输。

UDP协议不可传输协议:一般用于多媒体体数据传输,例如音频,视屏

TCP协议的搭建流程:

-----------------------------客户端-----------------------------------

1.创建socket  

头文件:

      #include <sys/types.h>          /* See NOTES */

      #include <sys/socket.h>

函数原型:

       int socket(int domain, int type, int protocol);

参数一:IP协议          AF_INET             IPv4 Internet protocols          ip(7)

                            AF_INET6            IPv6 Internet protocols          ipv6(7)

                                     AF_IPX              IPX - Novell protocols

参数二:传输协议      SOCK_STREAM    ---》TCP协议

                      SOCK_DGRAM     ---》UDP协议

参数三:socket的属性    填写为0 默认属性

返回值:成功发回 新的socket文件描述符 ,失败返回  -1

2.链接服务器  connect  (难点!!!!!!!!重点!!!)

头文件:

        #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>

函数原型:

        int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数一:socket文件描述符

参数二:服务器信息结构体

参数三:服务器信息结构体的大小

返回值:链接成功返回0  链接失败返回-1

const struct sockaddr *addr 服务器信息结构体  他的所在路径为 /usr/include/linux/in.h

struct sockaddr  与 struct sockaddr_in 在使用上是等价的。

struct sockaddr_in结构体介绍:

struct sockaddr_in {

  __kernel_sa_family_t sin_family;
/* Address family协议族 IPV4 还是IPV6协议*/

  __be16 sin_port;
/* Port number端口号*/

  struct in_addr sin_addr;
/* Internet addressIP地址*/

}

 /* Internet address. */IP地址结构体

struct in_addr {

__be32
s_addr;

};

IP地址转换函数:

#include <sys/socket.h>

#include <netinet/in.h>  -》会与linux/in.h冲突,所以在加入点分10进制转换函数后要把原来那个头文件去掉

#include <arpa/inet.h>

in_addr_t inet_addr(const char *cp);   -》点分10进制转整形 

char *inet_ntoa(struct in_addr in);   -》整形转点分10进制类型

大小端格式:在网络通信中都使用大端格式进行通信(所以我们需要转换端口号)

大端格式:低地址存储高位字节

小段格式:低地址存储低位字节

   uint16_t htons(uint16_t hostshort); -》主机序转网络序

   uint16_t ntohs(uint16_t netshort);  -》网络序转主机序

--------------------------------服务器端----------------------------------------

1.创建socket  
头文件:
      #include <sys/types.h>          /* See NOTES */
      #include <sys/socket.h>
函数原型:
       int socket(int domain, int type, int protocol);
参数一:IP协议          AF_INET             IPv4 Internet protocols          ip(7)
                            AF_INET6            IPv6 Internet protocols          ipv6(7)
                                     AF_IPX              IPX - Novell protocols
参数二:传输协议      SOCK_STREAM    ->TCP协议
                      SOCK_DGRAM     -》UDP协议
参数三:socket的属性    填写为0 默认属性
返回值:成功发回 新的socket文件描述符 ,失败返回  -1

2.绑定socket

头文件:

        #include <sys/types.h>          /* See NOTES */

        #include <sys/socket.h>

函数原型:

         int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

参数一:创建的socket文件描述符

参数二:服务器绑定信息

参数三:服务器信息结构体的大小

返回值:成功返回0 ,失败返回-1

3.设置为监听socket

头文件:

         #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>

函数原型:

          int listen(int sockfd, int backlog);

 参数一:创建的socket文件描述符

 参数二:最大监听数  (同时可以接受多少个客户端的链接请求)

 返回值:成功返回0  失败返回-1.

4.链接服务器  (重点!!!) 他会阻塞等待客户端链接过来

头文件:

        #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>

函数原型:

          int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数一:监听的文件描述符

参数二:客户端的信息结构体(例如客户端的IP,端口号)

参数三:成功接受客户端的信息结构体大小

返回值:接受链接请求成功,返回一个新的文件描述符,失败返回-1

--------------------------------------------------------------------------------------------------------------------------------------

练习:tcp服务器和客户端的简单通信实现

【server.c】

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
//写操作
void *write_fun(void *arg)
{
int fd=*(int *)arg;
char buf[50]={0};
//输入指令
while(1)
{
scanf("%s",buf);
write(fd,buf,strlen(buf));
}
}
//读操作
void *read_fun(void *arg)
{
int fd=*(int *)arg;
char buf[50]={0};
//输入指令
while(1)
{

bzero(buf,50);
read(fd,buf,50);
printf("buf=%s\n",buf);
}
}

int main(int argv,char **argc)
{
if(argv<3)
{
perror("plese input  ./server  prot  ip");
return 0;
}

//1.创建TCP socket
int sockfd=socket( AF_INET,SOCK_STREAM ,0);
if(sockfd<0)
{
perror("create sock fail\n");
}
else
{
printf("create sock %d\n",sockfd);
}
//设置服务器绑定信息
struct sockaddr_in  serveraddr;
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family  = AF_INET ;  //IPV4协议
serveraddr.sin_port    = htons(atoi(argc[1]));  //端口号
serveraddr.sin_addr.s_addr = inet_addr(argc[2]);//IP地址  "0.0.0.0" ->万用地址
// htonl(INADDR_ANY)   //INADDR_ANY  ->万用IP宏
//2.绑定服务器
int ret=bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
if(ret != 0)
{
perror("bind fail\n");
}
else
{
printf("bind ok\n");
}

//3.设置为监听socket
ret=listen(sockfd,5);
if(ret != 0)
{
perror("listen fail\n");
}
else
{
printf("listen ok\n");
}
//定义一个结构体保存客户端的信息
struct sockaddr_in  clienaddr;
bzero(&clienaddr,sizeof(clienaddr));
//定义一个整形保存接收的长度
socklen_t  len=sizeof(clienaddr);

//4.接收客户端的链接请求(重点!!!)
while(1)
{
int newfd=accept(sockfd,(struct sockaddr *)&clienaddr,&len);
if(newfd>0)
{
printf("accept OK fd=%d\n",newfd);
printf("clien ip=%s,port=%d\n",inet_ntoa(clienaddr.sin_addr),ntohs(clienaddr.sin_port));

//写入信息携程
pthread_t pid;
pthread_create(&pid,NULL,write_fun,(void *)&newfd);

//读取信息线程
pthread_t pid1;
pthread_create(&pid1,NULL,read_fun,(void *)&newfd);
}
else
{
perror("accept fail\n");
}
}
}


----------------------------------------------------------------------------------------------------------------------------------------------

【client.c】

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void *write_fun(void *arg)
{
int fd=*(int *)arg;
char buf[50]={0};
//输入指令
while(1)
{
scanf("%s",buf);
write(fd,buf,strlen(buf));
}
}

int main(int argv,char **argc)
{
if(argv<3)
{
perror("plese input  ./clien  prot  ip");
return 0;
}

//创建TCP socket
int sockfd=socket( AF_INET,SOCK_STREAM ,0);
if(sockfd<0)
{
perror("create sock fail\n");
}
else
{
printf("create sock %d\n",sockfd);
}
//设置服务器信息
struct sockaddr_in  serveraddr;
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family  = AF_INET ;  //IPV4协议
serveraddr.sin_port    = htons(atoi(argc[1]));  //端口号
serveraddr.sin_addr.s_addr = inet_addr(argc[2]);//IP地址

//进行读写操作
char buf[50]={0};

//链接服务器
int ret=connect(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
if(ret != 0)
{
perror("connect fail\n");
}
else
{
//使用一个写入线程
pthread_t pid;
pthread_create(&pid,NULL,write_fun,(void *)&sockfd);

while(1)
{
bzero(buf,sizeof(buf));
ret=read(sockfd,buf,sizeof(buf));
if(ret>0)
{
printf("buf=%s\n",buf);
}
else
{
perror("read fail\n");
return 0;
}
}
}
//写一个简单的聊天客户端  可以进行读写操作
}


-----------------------------------------------------------------------------------------------------------

程序运行时必须先运行服务器程序,再运行客户端程序,并且设置端口和服务器ip地址



    

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  TCP