Socket简介

Socket,这是一个老生常谈的话题,我只是梳理一下其相关知识点。
Socket is a port。在Linux中,网络编程是通过Socket接口来完成的。Socket接口是一种特殊的I/O,也是一种文件描述符。
一个Socket 用一个半相关描述: {协议,本地地址,本地端口}。
通过IP可以建立网络中两个设备之间的连接。通过Sockets使用TCP/UDP服务来建立网络中两个应用程序或进程之间的连接。

Socket系统调用包括:socket()、bind()、listen()、accept()、connect()、send()/sendto()、recv()/recvfrom()、read()、write()、close()、shutdown()。

connect()、recv()、send()、read()、write()、都属于阻塞性函数,若资源没有准备好,调用该函数的进程将进入睡眠状态,无法处理I/O多路复用的情况。
fcntl()和select()函数可以用来解决多路复用问题。fcntl()可以实现非阻塞I/O或信号驱动I/O;select()对CPU资源的利用率更高,功能更加强大。

TCP协议中,Socket的服务端和客户端交互:


UDP协议中,Socket的服务端和客户端交互:


一个简单的Linux TCP-Socket编程模型:
请包含头文件:stdio.h、sys/types.h、sys/socket.h、netinet/in.h、arpa/inet.h
server端:tcp_server.c

#include 
#include 
#include 
#include 
#include 

#define BUFSIZE 100

int main(int argc, char *argv[])
{
int sockfd;
int fd;
int len;
struct sockaddr_in server_addr; //server网络地址结构体
struct sockaddr_in client_addr; //client网络地址结构体
int sin_size;
char buf[BUFSIZE];
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; //设置为IP通信
server_addr.sin_addr.s_addr = INADDR_ANY; //服务器IP地址---允许连接到所有本地地址上
server_addr.sin_port = htons(8000); //server port

//get a socket fd TCP类型
if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
return -1;
}

//绑定
if( bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0)
{
perror("bind");
return -1;
}
//监听连接请求----监听队列长度为6
listen(sockfd, 6);
sin_size = sizeof(struct sockaddr_in);

//wait for client
if( (fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size)) < 0)
{
perror("accept");
return -1;
}

printf("accept client %s \n", inet_ntoa(client_addr.sin_addr));
len = send(fd, "Welcome to my server\n", 21, 0); //连接成功后,发送欢迎消息
//接收客户端的数据并将其发送给客户端--recv返回接收到的字节数,sand返回发送的字节数
while( (len = recv(fd, buf, BUFSIZE, 0)) > 0)
{
buf[len] = '\0';
printf("%s\n", buf);
if(send(fd, buf, len, 0) < 0)
{
perror("write");
return -1;
}

}

close(fd);
close(sockfd);
return 0;
}


client端:tcp_server.c

#include 
#include 
#include 
#include 
#include 

#define BUFSIZE 100
int main(int argc, char *argv[])
{
int sockfd;
int len;
struct sockaddr_in client_addr;
char buf[BUFSIZE];
memset(&client_addr, 0, sizeof(client_addr));//数据初始化--清零
client_addr.sin_family = AF_INET; //设置为IP通信
client_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //服务器IP地址
client_addr.sin_port = htons(8000); //服务器端口号

//创建客户端套接字
if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
return -1;
}
//将套接字绑定到服务器的网络地址上
if(connect(sockfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)) < 0)
{
perror("connect");
return -1;
}

printf("connected to server\n");
len = recv(sockfd, buf, BUFSIZE, 0);//接收服务器端信息
buf[len] = '\0';
//循环的发送接收信息并打印接收信息--recv返回接收到的字节数,sand返回发送的字节数
while(1)
{
printf("Enter string to send:\n");
scanf("%s", buf);
if(!strcmp(buf, "quit"))
{
break;
}

len = send(sockfd, buf, strlen(buf), 0);
len = recv(sockfd, buf, BUFSIZE, 0);
buf[len] = '\0';
printf("received: %s", buf);
}
close(sockfd);
return 0;
}


下面则为一个简单的Linux UDP-Socket编程模型:
server端:udp_server.c

#include 
#include 
#include 
#include 
#include 

#define BUFSIZE 100

int main(int argc, char *argv[])
{
int sockfd;
int fd;
int len;
struct sockaddr_in server_addr;//服务器网络地址结构体
struct sockaddr_in client_addr;//客户端网络地址结构体
int sin_size;
char buf[BUFSIZE];//数据传送的缓冲区
memset(&server_addr, 0, sizeof(server_addr));//数据传送的缓冲区
server_addr.sin_family = AF_INET; //设置为IP通信
server_addr.sin_addr.s_addr = INADDR_ANY; //服务器IP地址--允许连接到所有本地地址上
server_addr.sin_port = htons(8088); //服务器端口号
//创建服务器端套接字--IPv4协议,面向无连接通信,UDP协议
if((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
return -1;
}

//将套接字绑定到服务器的网络地址上
if(bind(sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0)
{
perror("bind");
return -1;
}
printf("socket begin receive...\n");

//接收客户端的数据并将其发送给客户端--recvfrom是无连接的
if((len = recvfrom(sockfd, buf, BUFSIZE, 0, (struct sockaddr*)&client_addr, &sin_size)) < 0)
{
perror("recvfrom");
return -1;
}

printf("received packet from %s:\n", inet_ntoa(client_addr.sin_addr));
buf[len] = '\0';
printf("contents: %s\n", buf);
close(sockfd);
return 0;
}


client端:udp_client.c

#include 
#include 
#include 
#include 
#include 

#define BUFSIZE 100
int main(int argc, char *argv[])
{
int sockfd;
int len;
int sin_size;
struct sockaddr_in client_addr;
char buf[BUFSIZE];
memset(&client_addr, 0, sizeof(client_addr));//数据初始化--清零
client_addr.sin_family = AF_INET; //设置为IP通信
client_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //服务器IP地址
client_addr.sin_port = htons(8088); //服务器端口号

//创建客户端套接字,面向无连接通信,UDP协议
if( (sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
return -1;
}

strcpy(buf, "I am a udp messager!");
sin_size = sizeof(struct sockaddr_in);

//send to server
if((len = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&client_addr, sizeof(struct sockaddr))) < 0)
{
perror("sendto");
return -1;
}
printf("sending: '%s'\n", buf);

close(sockfd);
return 0;
}

Socket API相关说明:
因为Socket对象是一类特殊的文件,所以可以用Linux系统I/O系统调用read和write函数,来读/写Socket对象。这两个函数对Socket的读写操作默认是以阻塞的方式进行的。
对Socket调用write()行为与将第4个参数flags设置为0的send()的行为完全相同。
通信的类型有本机通信(AF_UNIX/AF_LOCAL)和网络通信(AF_INET)。
端口号的选择:小于1024的端口号是系统所保留的,用户不能随便使用。
在TCP-Socket中,客户端也可以选择监听(listen),但一般不这样做。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值