C/C++教程

Socket网络编程之TCP编程——代码

本文主要是介绍Socket网络编程之TCP编程——代码,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录

主机字节序列

网络字节序列

套接字地址

通用socket地址结构

专用socket地址结构

IP地址转换函数

网络编程接口

TCP编程流程

服务端代码

客户端代码


关于网络编程这一块会涉及一些关于计算机网络的知识,包括网络分层、网络协议、端口号、IP地址等,不了解的地方可以自己查阅了解一下。这里简单的提一下主机字节序列和网络字节序列。

主机字节序列

主机字节序列分为大端字节序和小端字节序,不同的主机采用的字节序列可能不同。大端字节序是高位字节存储在内存低地址,低位字节存储在高地址;而小端则是高位字节存储在高地址,低位字节存储在低地址处。

这就会产生一个问题:在使用两台主机传递数据时,如果两台主机的主机字节序不同,那么就可能产生冲突。所以就引出了网络字节序列。

网络字节序列

在将数据发送到网络时规定整形数据使用大端字节序,所以把大端字节序称为网络字节序列

Linux 系统提供如下 4 个函数来完成主机字节序和网络字节序之间的转换:

 

套接字地址

套接字:通过网络进行数据收发

套接字地址一般是一组数组

通用socket地址结构

#include<bits/socket.h>

struct sockaddr
{
    sa_family_ sa_family;
    char sa_data[14];
};

地址族类型通常与协议族类型对应,常见的协议族和对应的地址族如下:

专用socket地址结构

TCP/IP协议族有sockaddr_in和sockaddr_in6两个专用socket地址结构体,分别用于IPV4和IPV6;

IP地址转换函数

#include <arpa/inet.h>

in_addr_t inet_addr(const char *cp); //字符串表示的IPV4地址转化为网络字节序
char* inet_ntoa(struct in_addr in);  //IPV4地址的网络字节序转化为字符串表示

网络编程接口

简单的介绍一下

#include<sys/types.h>
#include<sys/socket.h>

int socket(int domain,int type,int protocol);
//创建套接字,domain指套接字的协议簇,type指套接字的服务类型,protocol指协议:0为默认协议

int bind(int sockfd,const struct sockaddr* addr,socklen_t addrlen);
//将sockfd与socket地址绑定
//sockfd是网络套接字描述符

int connect(int sockfd,const struct sockaddr* serv_addr,socklen_t addrlen);
//客户端和服务器建立连接

int close(int sockfd);
//关闭连接

ssize_t recv(int sockfd, void *buff, size_t len, int flags);
//读取sockfd上的数据,buff和len参数分别指定读缓冲区的位置和大小

ssize_t send(int sockfd, const void *buff, size_t len, int flags);
//往socket上写入数据,buff和len参数分别指定写缓冲区的位置和数据长度

TCP编程流程

首先,tcp提供的是面向链接的,可靠的流式服务。主要流程如下:

服务端代码

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

int main()
{
   int sockfd=socket(AF_INET,SOCK_STREAM,0);
   assert(sockfd!=-1);
   
   struct sockaddr_in saddr,caddr;
   memset(&saddr,0,sizeof(saddr));
   saddr.sin_family=AF_INET;
   saddr.sin_port=htons(6000);//主机字节序列
   saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//回环地址,用于测试
   int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
   assert(res!=-1);

   res=listen(sockfd,5);//监听   
   assert(res!=-1);

   while(1)
{
      int len=sizeof(caddr);
      int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//可能阻塞
      if(c<0)
      {
         continue;
      }
      printf("client ip:%s,port:%d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
      printf("accept c=%d\n",c);
      char buff[128]={0};
      int n=recv(c,buff,127,0);//可能阻塞
      printf("recv(%d)=%s\n",n,buff);
      send(c,"ok",2,0);
      close(c);
   }
}

客户端代码

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

int main()
{
   int sockfd=socket(AF_INET,SOCK_STREAM,0);
   assert(sockfd!=-1);
   
   struct sockaddr_in saddr;
   memset(&saddr,0,sizeof(saddr));
   saddr.sin_family=AF_INET;
   saddr.sin_port=htons(6000);
   saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
   int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
   //发起连接
   assert(res!=-1);
   printf("input:\n");
   char buff[128]={0};
   fgets(buff,128,stdin);

   send(sockfd,buff,strlen(buff),0);
   memset(buff,0,128);
   recv(sockfd,buff,127,0);
   printf(%s\n,buff);
   close(sockfd);
}

执行结果:

今天先给代码,关于三次握手和四次挥手,以及多进程并发处理明天接着总结。

这篇关于Socket网络编程之TCP编程——代码的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!