地址:ip+端口号
数据:协议(数据格式)
socket:
tcp:面向连接
udp:面向报文,不可靠,但数据量大
TCP/UDP对比
1.TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2.TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3.TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信5. TCP首部开销20字节;UDP的首部开销小,只有8个字节
6.TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
字节序
步骤
API
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
socket服务器端代码demo
/*socket服务器端代码小demo*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
//int socket(int domain, int type, int protocol);创建套接字
//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);为套接字绑定IP和端口号
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int main(int argc,char **argv)
{
int n_read;
int so_fd;
int clen;
int cl_fd;
char readBuf[128]={"\0"};
char mesg[128] = {"\0"};
int mark = 0;
if(argc != 3){
printf("too few arguments\n");
exit(-1);
}
//1.socket创建套接字
so_fd = socket(AF_INET,SOCK_STREAM,0);//IPV4因特网域,tcp协议,返回套接字描述符
if(so_fd == -1){
perror("socket");
exit(-1);
}
//2.bind绑定IP地址端口号
struct sockaddr_in so_addr;
memset(&so_addr,0,sizeof(struct sockaddr_in));//初始化数据为0
so_addr.sin_family = AF_INET;//协议族,IPV4因特网域
so_addr.sin_port = htons(atoi(argv[2]));//端口号,由主机转换成网络字节序
inet_aton(argv[1],&so_addr.sin_addr);//IP地址,由字符串转换成网络格式
bind(so_fd,(struct sockaddr*)&so_addr,sizeof(struct sockaddr_in));//结构体替换成另一个类型,但参数已经定义了类型,所以强转回原来的类型
//3.listen监听
listen(so_fd,10);
//4.连接接受
struct sockaddr_in cl_addr;
clen = sizeof(struct sockaddr_in);
while(1){
memset(&cl_addr,0,sizeof(struct sockaddr_in));//初始化数据为0
cl_fd = accept(so_fd,(struct sockaddr *)&cl_addr,&clen);//返回新建立通道fd,和客户端的信息
if(cl_fd == -1){
perror("accept");
}else{
printf("connect to client,IP:%s,port:%d\n",inet_ntoa(cl_addr.sin_addr),ntohs(cl_addr.sin_port));//网络格式IP转换成字符串形式
}
mark++;//标记接入客户端数
if(fork() == 0){//创建子进程处理客户端,这样父进程可以继续等待其它客户端连接
if(fork()==0){//创建子进程,让发送和接受信息能同时进行
while(1){
//5.read
memset(readBuf,0,sizeof(readBuf));//清空数组里面的历史数据
n_read = read(cl_fd,readBuf,128);//从客户端读取数据到数组缓冲区
if(n_read == -1){
perror("read");
}else if(n_read > 0){
printf("client:%d,%s\n",n_read,readBuf);//打印数据
}else if(n_read == 0){
printf("client offline\n");//客户端关掉进程后发送FIN到服务端,然后系统给read函数发信号,告知read函数无数据,于是read函数马上返回0。
break;
}
}
}
while(1){
//6.send
sprintf(mesg,"Hello! NO.%d client\n",mark);
write(cl_fd,mesg,strlen(mesg));//发数据到客户端
sleep(8);
}
}
}
return 0;
}
/*client*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
//int socket(int domain, int type, int protocol);创建套接字
//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);为套接字绑定IP和端口号
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int main(int argc,char **argv)
{
int n_read;
int cl_fd;
char readBuf[128]={0};
char mesg[128] = {0};
if(argc != 3){
printf("too few arguments\n");
exit(-1);
}
//1.创建套接字
cl_fd = socket(AF_INET,SOCK_STREAM,0);//IPV4因特网域,tcp协议,返回套接字描述符
if(cl_fd == -1){
perror("socket");
exit(-1);
}
//2.设置IP地址端口号
struct sockaddr_in cl_addr;
memset(&cl_addr,0,sizeof(struct sockaddr_in));//初始化数据为0
cl_addr.sin_family = AF_INET;//协议族,IPV4因特网域
cl_addr.sin_port = htons(atoi(argv[2]));//端口号,由主机转换成网络字节序
inet_aton(argv[1],&cl_addr.sin_addr);//IP地址,由字符串转换成网络格式
//3.连接
int ret = connect(cl_fd,(struct sockaddr *)&cl_addr,sizeof(struct sockaddr_in));
if(ret == -1){
perror("connect");
exit(-1);
}
while(1){
if(fork()==0){//创建子进程,让发送和接受信息能同时进行
while(1){
//4.read
memset(readBuf,0,sizeof(readBuf));//清空数组里面的历史数据
n_read = read(cl_fd,readBuf,128);//从服务器读取数据到数组缓冲区
if(n_read == -1){
perror("read");
}else if(n_read >0){
printf("server:%d,%s\n",n_read,readBuf);//打印服务器来的数据
}else if(n_read == 0){
printf("server close\n");
return 0;
}
}
}
while(1){
//5.send
memset(mesg,0,sizeof(mesg));
printf("input:\n");
gets(mesg);
write(cl_fd,mesg,strlen(mesg));//发数据到服务器
}
}
return