1、socket 网络套接字linux
建立
函数原型:
int socket(int domain, int type, int protocol);
参数说明:
domain:协议域,又称协议族(family)。经常使用的协议族有AF_INET、AF_INET六、AF_LOCAL(或称AF_UNIX,Unix域Socket)、AF_ROUTE等。协议族决定了socket的地址类型,在通讯中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名做为地址。
type:指定Socket类型。经常使用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一种面向链接的Socket,针对于面向链接的TCP服务应用。数据报式Socket(SOCK_DGRAM)是一种无链接的Socket,对应于无链接的UDP服务应用。
protocol:指定协议。经常使用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
注意:1.type和protocol不能够随意组合,如SOCK_STREAM不能够跟IPPROTO_UDP组合。当第三个参数为0时,会自动选择第二个参数类型对应的默认协议。
2.WindowsSocket下protocol参数中不存在IPPROTO_STCP
2、sockaddr_in
sockaddr_in(在netinet/in.h中定义):
1
2
3
4
5
6
7
8
9
10
11
12
13
struct sockaddr_in
{
short sin_family;/*Address family通常来讲AF_INET(地址族)PF_INET(协议族)*/
unsigned short sin_port;/*Port number(必需要采用网络数据格式,普通数字能够用htons()函数转换成网络数据格式的数字)*/
struct in_addr sin_addr;/*IP address in network byte order(Internet address)*/
unsigned char sin_zero[8];/*Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐*/
};
in_addr结构
1
2
3
4
5
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号(使用网络字节顺序),在linux下,端口号的范围0~65535,同时0~1024范围的端口号已经被系统使用或保留。
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址
3、绑定编程
int bind(SOCKET socket, const struct sockaddr* address, socklen_t address_len);
参数说明:
socket:是一个套接字描述符。
address:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号。
address_len:肯定address缓冲区的长度。
返回值:
若是函数执行成功,返回值为0,不然为SOCKET_ERROR。
4、接收服务器
函数原型:
ssize_t recvfrom(int sockfd, void buf, int len, unsigned int flags, struct socketaddr* from, socket_t* fromlen);
参数说明:
sockfd:标识一个已链接套接口的描述字。
buf:接收数据缓冲区。
len:缓冲区长度。
flags:调用操做方式。是如下一个或者多个标志的组合体,可经过or操做连在一块儿:
from:(可选)指针,指向装有源地址的缓冲区。
fromlen:(可选)指针,指向from缓冲区长度值。
5、发送网络
函数原型:
int sendto( SOCKET s, const char FAR* buf, int size, int flags, const struct sockaddr FAR* to, int tolen);
参数说明:
s:套接字
buf:待发送数据的缓冲区
size:缓冲区长度
flags:调用方式标志位, 通常为0, 改变Flags,将会改变Sendto发送的形式
addr:(可选)指针,指向目的套接字的地址
tolen:addr所指地址的长度
返回值:
若是成功,则返回发送的字节数,失败则返回SOCKET_ERROR。数据结构
服务器端代码:dom
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>socket
int main(int argc,char *argv[])
{
if(argc!=3)
{
printf("Usage ./server [ip] [port]\n");
return 1;
}
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0)
{
perror("socket");
return 2;
}函数
struct sockaddr_in local;ui
local.sin_family=AF_INET;//ipv4
local.sin_port=htons(atoi(argv[2]));//主机字节序转换为网络字节序
local.sin_addr.s_addr=inet_addr(argv[1]);//字符串转in_addr的函数.net
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
return 3;
}
char buf[1024];
struct sockaddr_in client;
while(1)
{
socklen_t len=sizeof(client);
ssize_t s=recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&client,&len);
if(s>0)
{
buf[s]=0;
printf("[%s:%d]:%s\n",inet_ntoa(client.sin_addr),\
ntohs(client.sin_port),buf);
sendto(sock,buf,strlen(buf),0, \
(struct sockaddr*)&client,sizeof(client));
}
}
close(sock);
return 0;
}
客户端的代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main(int argc,char *argv[])
{
if(argc!=3)
{
printf("./Usage [ip] [port]\n");
return 1;
}
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0)
{
perror("socket");
return 2;
}
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(atoi(argv[2]));
server.sin_addr.s_addr=inet_addr(argv[1]);
char buf[1024];
struct sockaddr_in peer;
while(1)
{
socklen_t len=sizeof(peer);
printf("Please Enter# ");
fflush(stdout);
ssize_t s=read(0,buf,sizeof(buf)-1);
if(s>0)
{
buf[s-1]=0;
sendto(sock,buf,strlen(buf),0,\
(struct sockaddr*)&server,sizeof(server));
ssize_t _s=recvfrom(sock,buf,sizeof(buf)-1,0,\
(struct sockaddr*)&peer,&len);
if(_s>0) { buf[_s]=0; printf("server echo# %s\n",buf); } } } close(sock); return 0; }