1.用socket()函数创建socket,返回值为socket的标识符sockfd,这个标识符在后面都会用到
2.用结构体sockaddr_in去保存服务器信息(协议,端口,ip)
联合体成员:struct sockaddr_in sever_addr{
sever_addr.sin_family //协议
sever_addr.sin_port //端口,一般大于1024
sever_addr.sin_addr.s_addr //ip
}
3.用bind()函数绑定信息
注意:第二个参数要强转成(struct sockaddr *)类型
4.用sockaddr_in函数保存客户端信息
6.在while循环里面用recvfrom()函数不停的接收信息并打印
7.用close函数关闭socket
服务器代码:
#include
#include /* See NOTES */
#include
#include
#include
#include
#include
#include
int main()
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); //IPV4协议 数据包套接字
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
struct sockaddr_in server_addr; //用于保存服务器信息
memset(&server_addr, 0, sizeof(server_addr)); //清零
server_addr.sin_family = AF_INET; //协议
server_addr.sin_port = 8000; //端口
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //ip地址
//绑定信息
int ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(-1 == ret)
{
perror("bind");
exit(1);
}
char buf[32] = {0};
struct sockaddr_in client_addr; //用于保存客户端信息
int length = sizeof(client_addr);
while(1)
{
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &length);
if(-1 == ret)
{
perror("recvfrom");
exit(1);
}
printf("接收%d : %s\n", client_addr.sin_port, buf);
memset(buf, 0, sizeof(buf));
}
return 0;
}
1.用socket()函数创建socket,返回值为socket的标识符sockfd,后面都会用到标识符
2.用sockaddr_in 结构体保存服务器信息
3.在while循环里面
4.用sendto()函数不停的发送信息
5.用close函数关掉socket
客户端代码:
#include
#include /* See NOTES */
#include
#include
#include
#include
#include
#include
int main()
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
char buf[32] = {0};
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = 8000;
server_addr.sin_addr.s_addr =inet_addr("127.0.0.1");
int length = sizeof(server_addr);
while(1)
{
scanf("%s",buf);
int ret = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&server_addr, length);
if(-1 == ret)
{
perror("sendto");
exit(1);
}
if(!strcmp(buf, "bye"))
{
break;
}
memset(buf, 0, sizeof(buf));
}
close(sockfd);
return 0;
}
函数原型: 函数原型:ssize_t recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,socket_t *fromlen); ssize_t 相当于 int,socket_t 相当于int ,这里用这个名字为的是提高代码的自说明性。
功能: 经socket接收数据
参数:
sockfd:标识一个已连接套接口的描述字。
buf:接收数据缓冲区。
len:缓冲区长度。
flags:调用操作方式。是以下一个或者多个标志的组合体,可通过or操作连在一起:(默认为0)
from:客户端结构体名的地址 (需要强转成(struct sockaddr *)类型)
fromlen:客户端结构体长度的地址
返回值: 成功则返回接收到的字符数,失败返回-1.
函数原型: ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
功能: 使用指定的 sockfd,将指定字节数的数据发送到指定的终结点。
参数:
sockfd:正在监听端口的套接口文件描述符,通过socket获得
buf:发送缓冲区,往往是使用者定义的数组,该数组装有要发送的数据
len:发送缓冲区的大小,单位是字节
flags:填0即可
dest_addr:指向接收数据的主机地址信息的结构体,也就是该参数指定数据要发送到哪个主机哪个进程
addrlen:表示第五个参数所指向内容的长度
返回值: 成功返回发送成功的数据长度,失败返回-1
函数原型: int socket(int sockfd, int type, int protocol);
功能: 用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。
参数:
第一个参数: 即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
第二个参数: 指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。
第三个参数(默认为0): 指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
注意: 并不是上面的type和protocol可以随意组合的,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议。
返回值: 成功的话返回socket的标示符sockid,失败的话返回-1;
函数原型: int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能: 把一个地址族中的特定地址赋给socket。当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。
参数:
第一个参数: 即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。
第二个参数: 一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同,如ipv4对应的是:
struct sockaddr_in server_addr{
server_addr.sin_family = AF_INET;
server_addr.sin_port = 800;
server_addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
};
注意要强转成struct sockaddr类型
第三个参数: 对应的是地址的长度。
返回值: 成功返回0,失败返回-1;
通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。
就好像操作完打开的文件要调用fclose关闭打开的文件,在读写完成之后最后关闭文件。
函数原型: int close(int fd);
参数: 套接字描述符 socket函数和accept函数的返回值;