互联网编程

在互连网上,通讯服务都是运用C/S机制,约等于客户端/服务器机制。流程可以参见下图:

TCP通信
(一) tcp实验
ip 用途,唯一识别机具
port 用来绑定程序,即端口用来识别程序

图片 1

服务端
//1.创建socket
#include <sys/types.h> //常用项目
#include <sys/socket.h> //socket函数等
int socket(int domain, int type, int pro-tocol);
重回值,是设备的讲述符 失利重临 -1
参数:
domain: AF_INET 当前采取的
type: 协议项目 套接字类型
TCP 文件 SOCK_STREAM 流式套接字
UDP qq SOCK_DGRAM 数据报
ICMP ping SOCK_RAM 原始套接字
pro-tocol 协义簇类型
0 符合协议簇和套接字类型的暗中认同协议 寻常设为0

劳动器端工作流程:

//3.开行侦听
int listen(int sockfd, int backlog);
参数:sockfd: 服务端套接字描述符 socket重返的值
backlog: 钦定排队等候接受连接的最大值 系统最大值SOMAXCONN
返回值:0成功 -1失败

运用socket()函数成立服务器端通讯套接口

//4.经受连接请求
int accept(int sockfd,struct sockaddr *addr, size_t *addrlen);
参数:sockfd: 服务端套接字描述符
addr: 获取过来的客户的地点新闻
addrlen:获取过来的客户的位置音讯长度
重返值:成功 重返的是与客户端举办通讯用的套接字描述符 战败-1
总得是循环等待接受连接请求.

行使bind()函数将创设的套接口与服务器地址绑定

//5.数据收发
ssize_t recv(int s, void *buf, size_t len, int flags);
ssize_t send(int s, const void *buf, size_t len, int flags);
参数:s: 套接字描述符
服务端:是accept返回值
客户端: 是socket返回值
buf:内存地址
len:数据长度
flags 标志位
0 阻塞
MSG_DONTWAIT 非阻塞

动用listen()函数使服务器套接口做好采取屡次三番请求准备

//6.关闭描述
int close(int fd);

选取accept()接收来自客户端由connect()函数发出的连接请求

//2.绑定 把ip和port与程序捆绑在一齐
int bind(int sockfd,struct sockaddr *addr,size_t addrlen);
参数:sockfd是socket再次来到的讲述符
addr 指向套字地址结构的指针 本机的地方和端口
addrlen:结构体长度
返回值:0 成功,-1 失败

依据连年请求建立连接后,使用send()函数发送数据,可能选择recv()函数接收数据

1)struct sockaddr结构体
struct sockaddr{
short sa_family; //钦定的地址簇,AF_INET
char sa_data[14]; //IP地址,端口号
};
平常用另一种结构来填写
struct sockaddr_in{
short sin_family; //内定的地址簇,地址簇和协议簇相同,AF_INET
short sin_port; //端口号
struct in_addr sin_addr; //IP地址
char sin_zero[8];
};
struct in_addr{
unsigned long s_addr;
};
2)IP地址和端号
积存ip和端口时,用互连网字节序来存储
b.端口号sin_port
0 代表由系统自动随机分配端口号。
其他值 为用户钦命的端口号
注:客户端可以设置为0,服务器端无法设为0。 在服务端一般内定端口号 ushort
0-65535
c.IP地址sin_addr
INADDR_ANY 代表可以由系统将本机上保有的IP举办绑定大多用于服务器端
其余值 为用户端指定要绑定的IP

动用closesocket()函数关闭套接口(可以先用shutdown()函数先关闭读写通道)

d.字节序
in_addr_t inet_addr(char *cp); //把字符串格ip变字节序
uini16_t htons(uini16_t hostshort); //把端口号变字节序

客户端程序工作流程:

客户端
//.1
socket
//.2 连接服务器
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t
addrlen);
参数:sockfd:客户端套接字描述符
serv_addr:客户端填写的要延续的服务器的地方
addrlen : 地址音讯长度
//.3
recv
send
//.4
close

拔取socket()函数创设客户端套接口

利用connect()函数发出也服务器建立连接的呼吁(调用前可以不要bind()端口号,由系统活动达成)

总是建立后选用send()函数发送数据,或利用recv()函数接收数据

利用closesocet()函数关闭套接口

下边介绍多少个函数的用法:

socket函数:int socket(int domain,int
type,int protocol)

参数表明:
domain:指明协议族,也称为协议域,是3个常值。
AF_INET:IPv4 协议
AF_INET6:IPv6 协议
AF_LOCAL/AF_UNIX:Unix协议域
AF_ROUTE: 路由套接字
AF_KE:密匙套接字

type:指明套接字的连串。
SOCK_STREA:字节流套接字
SOCK_DGRA:数据报套接字
SOCK_SEQPACKE:有序分组套接字
SOCK_RAW:原始套接字

protocol: 指明协议项目。一般为0,以采用给定的domain和type组合的系统暗中认可值。
IPPROTO_TCP:TCP传输协议
IPPROTO_UDP:UDP传输协议
IPPROTO_SCTP:SCTP传输协议

函数描述:
socket
函数在成功时重临1个小的非负整数值,与公事讲述符类似,大家称它为套接字
描述符,简称 sockfd。为了得到那么些套接字描述符,我们只是内定了协议族(IPv四 、IPv6
或Unix)和套接字类型(字节流、数据报或原始套接字)。大家并没有点名地点跟远程的
探讨地址

bind函数:int bind(int sockfd, const struct sockaddr
*myaddr, socklen_t addrlen);

将3个本土协议地址赋予一个套接字。对于网际网协议,协议地址是3一个人的IPv4地址和128
位的IPv6地址与拾三个人的TCP或UDP端口号的结缘。bind
函数根本用以服务器端,用来指定地方
长机的哪些网络接口(IP,能够是INADDTiggo_ANY,表示当地主机的任一互连网接口)还是可以客户
端的请求,和钦点端口号(即打开的等待客户来连接的经过)。

参数表明:

sockfd: socket
函数再次回到的套接字描述符。

myaddr、addrlen:指向三个套接字地址结构的指针和该协会的分寸。

地方结构的貌似拔取sockadr_in结构体

struct
sockaddr_in{

short int sin_family;
#地址族

unsigned short int
sin_port; #端口号

struct n_addr sin_addr;
#IP地址

unsigned char
sin_zeor[8]; #填充0保持与struct
sockaddr同样大小

}

 

listen函数:

int listen(int sockfd,int
backlog)

listen函数的率先个参数即为要监听的socket描述字,第一个参数为对应socket可以排队的最阿比让接个数。socket()函数成立的socket暗中认同是一个主动类型的,listen函数将socket变为被动类型的,等待客户的总是请求。

Connetc函数:

connect函数的首先个参数即为客户端的socket描述字,第1参数为服务器的socket地址,第几个参数为socket地址的长度。客户端通过调用connect函数来树立与TCP服务器的总是

accept函数:

int accept(int
sockfd,struct sockaddr *addr, socketen_t
*add_len)

参数sockfd
参数sockfd就是上边表达中的监听套接字,那几个套接字用来监听一个端口,当有二个客户与服务器连接时,它利用那个1个端口号,而此刻这一个端口号正与那几个套接字关联。当然客户不知底套接字那几个细节,它只了然3个地点和一个端口号。

参数addr
那是二个结实参数,它用来经受三个重临值,那重回值钦赐客户端的地点,当然这一个地方是经过有个别地方结构来讲述的,用户应该明了那3个怎样的地点结构。若是对客户的地方不感兴趣,那么可以把这几个值设置为NULL。

参数len
似乎我们所认为的,它也是结果的参数,用来接受上述addr的布局的大大小小的,它指明addr结构所占用的字节个数。同样的,它也可以被安装为NULL。

万一accept成功再次回到,则服务器与客户已经不易树立连接了,此时服务器通过accept重回的套接字来达成与客户的通讯。

服务器测的代码如下:对于服务端来说,首先是创设socket然后绑定IP地址到socket上。然后开头监听。

当接过到请求的时候,通过recv函数存储在buf数组里面。并且经过send函数向对端发送音信

int server_function()
{
    char *sendbuf=”thanks”;
    char buf[256];
    int s_fd,c_fd;
    int s_len,c_len;
    struct sockaddr_in s_addr;
    struct sockaddr_in c_addr;
    s_fd=socket(AF_INET,SOCK_STREAM,0);
    s_addr.sin_family=AF_INET;
    s_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    s_addr.sin_port=PORT;
    s_len=sizeof(s_addr);
    bind(s_fd,(struct sockaddr *)&s_addr,s_len);
    listen(s_fd,10);
    while(1){
        printf(“please wait a moment\n”);
        c_len=sizeof(c_addr);
        c_fd=accept(s_fd,(struct sockaddr *)&c_addr,(socklen_t
*__restrict)&c_len);
        recv(c_fd,buf,256,0);
        buf[strlen(buf)+1]=’\0′;
        printf(“receve message:\n%s\n”,buf);
        send(c_fd,sendbuf,strlen(sendbuf),0);
        close(c_fd);
    }
}

 

 

客户端的代码如下:设置好连接的IP地址和端口后,通过connect发起连接。并透过send和recv函数进行发送和接到音讯

int client_function()
{
    char *buf=”come on”;
    char rebuf[250];
    int sockfd,len,newsockfd,len2;
    struct sockaddr_in addr;
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    addr.sin_family=AF_INET;
    addr.sin_addr.s_addr=htonl(INADDR_ANY);
    addr.sin_port=PORT;
    len=sizeof(addr);
    newsockfd=connect(sockfd,(struct sockaddr *)&addr,len);
    len2=strlen(buf);
    send(sockfd,buf,len2,0);
    sleep(5);
    recv(sockfd,rebuf,40,0);
    printf(“the length of the rebuf is %d”,strlen(rebuf));
    rebuf[strlen(rebuf)+1]=’\0′;
    printf(“receive message:\n%s\n”,rebuf);
    close(sockfd);
    return 0;
}

 

开辟一个极点,分别运维服务器和客户端的代码。执行结果如下:

图片 2