通信协议(OSI、TCP/IP)
OSI协议(七层网络协议)
下三层
1物理层(类似网卡(接收传输数据))
2链路层(解析数据)
3网络层(选择数据传送)
高四层
4传输层(提供端对端接口(传输数据))
5会话层(会话x,(解除或建立联系))
6表示层(表示x,(加密、转换))
7应用层(行动x(展示网络服务))TCP/IP协议(四层协议)
- TCP/IP 具有两个主要功能。第一是IP 在网络之间(有时在个别网络内部)提供路由选择。第二是TCP 将TP 传递的数据传送的接收主机那的适当的处理部件。
- 套接字(类似SIM卡)
套接字有三种类型:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)及原始套接字 - 流式套接字
流式的套接字可以提供可靠的、面向连接的通讯流。如果你通过流式套接字发送了顺序的数据:“1”、“2”。那么数据到达远程时候的顺序也是“1”、“2”。采用TCP协议
数据报套接字
一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错,使用者数据报协议UDP(User Datagram Protocol )
原始套接字
主要用于一些协议的开发,可以进行比较底层的操作
TCP协议:
三次握手:请求连接–>授权—>连接
四次关闭:客户端请求关闭—>服务端可以关了—>客户端关了—>服务端也关了
socket基本函数
htons() 主机字节顺序转换为网络字节顺序(对无符号短型进行操作4 bytes)
htonl() 主机字节顺序转换为网络字节顺序(对无符号长型进行操作8 bytes)
ntohs() 网络字节顺序转换为主机字节顺序(对无符号短型进行操作4 bytes)
ntohl() 网络字节顺序转换为主机字节顺序(对无符号长型进行操作8 bytes)
close() 关闭套接字,任何有关对套接字描述符进行读和写的操作都会接收到一个错误。
shutdown() 允许你进行单向的关闭操作,或是全部禁止掉(0不接 1不发 2全关)
setsockopt() 、 getsockopt() 设置和获取套接字的属性
getpeername() 获取连接上的远程信息
socket(TCP/IP)代码
-
- IP和主机地址处理
/******** IP和主机地址 *************/
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
/*
struct sockaddr_in{ //“in” 代表 “Internet”
short int sin_family; // Internet地址族
unsigned short int sin_port; // 端口号
struct in_addr sin_addr; // Internet地址
unsigned char sin_zero[8]; // 添0(和struct sockaddr一样大小)
};
*/
int main(int argc, char *argv[])
{
struct hostent *host;
//域名解析成IP
host = gethostbyname(argv[1]);
//字符串转成整型inet_addr()
printf("%d\n", inet_addr("166.111.69.52"));
printf("hostname == %s\n", host->h_name);
//整机转成字符串inet_ntoa()
printf("ip == %s\n", inet_ntoa(((struct in_addr *)(host->h_addr_list[0]))->s_addr));
return 0;
}
- 2.socket函数
//1.网络协议一般是AF_INET 2.TCP(SOCK_STREAM)或者UDP(SOCK_STREAM)3.一般为0
//int socket(int family , int type , int protocol); ------买电话机
//1.电话机2.绑定端口号码 3.
//int bind (int sockfd , struct sockaddr *my_addr , int addrlen) ;--------插线(2绑定到1上)
//1.电话机 2.同时监听的个数(一般5--10)
//int listen(int sockfd, int backlog); --------待机(监听)
//1.电话机 2.传过来的地址 3.
//int accept(int sockfd, void *addr, int *addrlen) ----------接听
- 3.基本socket的建立
/***********基本步骤(服务端.c)***********/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define PORT 4999
int main(int argc, char *argv[])
{
int sfd;
int accept_fd;
struct sockaddr_in addr;
struct sockaddr_in client_addr;
char buf[128];
int size;
int ret;
//创建socket
sfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(struct sockaddr_in));
//绑定端口
printf("===create socket===\n");
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
printf("===bind===\n");
bind(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
//监听
printf("===listen===\n");
listen(sfd, 10);
//接收
printf("===accept===\n");
size = sizeof(struct sockaddr);
accept_fd = accept(sfd, (struct sockaddr *)&client_addr, &size);
printf("===send===\n");
//读取或输出
memset(buf, 0, sizeof(buf));
strcpy(buf, "abc");
ret = send(accept_fd, buf,strlen(buf),0);
printf("==ret is:%d\n", ret);
sleep(10);
close(accept_fd);
close(sfd);
return 0;
return 0;
}
----------------------------------------------
/***********基本步骤(客户端.c)***********/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int sfd;
int accept_fd;
struct sockaddr_in addr;
struct sockaddr_in client_addr;
char buf[128];
int ret;
sfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(struct sockaddr_in));
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(4999);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = connect(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
memset(buf, 0, 128);
ret = recv(sfd, buf, 128, 0);
printf("===buf===:%s\n", buf);
close(sfd);
return 0;
}
- 3.复杂点的socket
/************实现多个客户端对一个客户端(服务端.C)*************/
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/time.h>
#include<sys/un.h>
#include<sys/ioctl.h>
#include<sys/wait.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define SERVPORT 1234
#define BACKLOG 20
#define MAX_CON_NO 10
#define MAX_DATA_SIZE 1024
void *deal_msg(void *arg)
{
int newfd;
char sendBuf[MAX_DATA_SIZE], recvBuf[MAX_DATA_SIZE];
int recvBytes, sendBytes;
pthread_detach(pthread_self());
newfd = *(int *)arg;
while(1) {
/* 接收*/
if((recvBytes = recv(newfd, recvBuf,
MAX_DATA_SIZE, 0)) == -1){
perror("fail to receive datas");
exit(1);
}
printf("client :%s\n", recvBuf);
memset(recvBuf, 0x00, MAX_DATA_SIZE);
/* 发送*/
printf("server:");
gets(sendBuf);
if((sendBytes = send(newfd, sendBuf,
strlen(sendBuf), 0)) != strlen(sendBuf)){
perror("fail to receive datas");
exit(1);
}
printf("(success to send data!)\n");
memset(sendBuf, 0x00, MAX_DATA_SIZE);
}
close(newfd);
return NULL;
}
int main(int argc, char *argv[])
{
struct sockaddr_in serverSockaddr, clientSockaddr;
int sinSize, recvBytes, sendBytes;
pthread_t tid;
int sockfd, clientfd;
//char mac[6];
if(argc != 1) {
printf("usage:./server\n");
exit(1);
}
/*establish a socket*/
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("fail to establish a socket");
exit(1);
}
printf("Success to establish a socket...(sockfd = %d)\n", sockfd);
/*init sockaddr_in*/
serverSockaddr.sin_family = AF_INET;
serverSockaddr.sin_port = htons(SERVPORT);
serverSockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bzero(&(serverSockaddr.sin_zero), 8);
int on = 1;
/*设置和套接字的属性*/
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
/*bind socket*/
if(bind(sockfd, (struct sockaddr *)&serverSockaddr,
sizeof(struct sockaddr))== -1) {
perror("fail to bind");
exit(1);
}
printf("Success to bind the socket...\n");
/*listen on the socket*/
if(listen(sockfd, BACKLOG) == -1) {
perror("fail to listen");
exit(1);
}
printf("Success to listen on the socket...\n");
while(1) {
sinSize = sizeof(struct sockaddr_in);
/*accept a client's request*/
if ((clientfd = accept(sockfd,
(struct sockaddr *)&clientSockaddr, &sinSize)) == -1) {
perror("fail to accept");
exit(1);
}
printf("success to accept=======\n");
/*改变打印颜色*/
printf("\033[40;32mWelcome to join %s!\033[1m\n",
inet_ntoa(clientSockaddr.sin_addr));
/* 创建线程实现信号传递 */
pthread_create(&tid, NULL, deal_msg, &clientfd);
}
}
-----------------------------------------------------------/************实现多个客户端对一个客户端(客户端.C)*************/
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define SERVPORT 1234
#define MAX_DATA_SIZE 1024
int main(int argc, char *argv[])
{
int sockfd, sendBytes,recvBytes;
char sendBuf[MAX_DATA_SIZE],recvBuf[MAX_DATA_SIZE];
struct hostent *host;
struct sockaddr_in servAddr;
if(argc != 2) {
fprintf(stderr,"usage:./client [hostname]");
exit(1);
}
/*translate the address*/
if((host = gethostbyname(argv[1])) == NULL) {
perror("fail to get host by name");
exit(1);
}
printf("Success to get host by name...\n");
/*establish a socket*/
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("fail to establish a socket");
exit(1);
}
printf("Success to establish a socket...\n");
/*init sockaddr_in*/
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(SERVPORT);
servAddr.sin_addr = *((struct in_addr *)host -> h_addr);
bzero(&(servAddr.sin_zero), 8);
/*connect the socket*/
if(connect(sockfd, (struct sockaddr *)&servAddr,
sizeof(struct sockaddr_in)) == -1) {
perror("fail to connect the socket");
goto _exit;
}
printf("Success to connect the socket...\n");
printf("\033[40;32mWelcome to join %s!\033[1m\n",
inet_ntoa(servAddr.sin_addr)); //include color set
while(1) {
/*send datas to server*/
printf("Client:");
gets(sendBuf);
if ((sendBytes = send(sockfd, sendBuf, strlen(sendBuf),0))
!= strlen(sendBuf)){
perror("fail to send data!\n");
goto _exit;
}
printf("(success to send data!)\n");
memset(sendBuf, 0x00, MAX_DATA_SIZE);
/*recive datas to server*/
if ((recvBytes = recv(sockfd, recvBuf, MAX_DATA_SIZE, 0)) == -1){
perror("fail to send data!\n");
goto _exit;
}
printf("server :%s\n", recvBuf);
memset(recvBuf, 0, MAX_DATA_SIZE);
}
_exit:
close(sockfd);
}
- 4.无限大小的数据传输socket
/*********服务端.c***************/
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/time.h>
#include<sys/un.h>
#include<sys/ioctl.h>
#include<sys/wait.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include "comm.h"
#include "lst.h"
#define SERVPORT 1234
#define BACKLOG 20
#define MAX_CON_NO 10
#define MAX_DATA_SIZE 1024
void *deal_msg(void *arg)
{
int newfd;
char http_buf[1500];
char sendBuf[MAX_DATA_SIZE], recvBuf[MAX_DATA_SIZE];
int recvBytes, sendBytes;
msg_head_t *msg;
char *msgbuf;
char buf[64];
int ret;
pthread_detach(pthread_srlf());
newfd = *(int *)arg;
while(1) {
memset(buf, 0, 64);
memset(&msg, 0 sizeof(msg_head_t));
ret = recv(newfd, &msg, sizeof(msg_head_t), 0);
msg = (msg_head_t *)buf;
recvBytes = msg.len;
printf("======recvBytes is :%d,%d\n", msg->len, ret);
msgbuf = malloc(recvBytes);
memset(msgbuf, 0, recvBytes);
recv(newfd, msgbuf, recvBytes, 0);
printf("==recv msgbuf:%s\n", msgbuf);
free(msgbuf);
break;
}
close(newfd);
return NULL;
}
int main(int argc, char *argv[]) {
struct sockaddr_in serverSockaddr, clientSockaddr;
int sinSize, recvBytes, sendBytes;
pthread_t tid;
int sockfd, clientfd;
int fdmax;
int ret;
int i = 0;
char mac[6];
fd_set readfs;
sock_array_t *pos, *pon;
if(argc != 1) {
printf("usage:./server\n");
exit(1);
}
/*establish a socket*/
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("fail to establish a socket");
exit(1);
}
printf("Success to establish a socket...(sockfd = %d)\n", sockfd);
/*init sockaddr_in*/
serverSockaddr.sin_family = AF_INET;
serverSockaddr.sin_port = htons(SERVPORT);
serverSockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bzero(&(serverSockaddr.sin_zero), 8);
int on = 1;
/*设置和套接字的属性*/
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
/*bind socket*/
if(bind(sockfd, (struct sockaddr *)&serverSockaddr,
sizeof(struct sockaddr))== -1) {
perror("fail to bind");
exit(1);
}
printf("Success to bind the socket...\n");
/*listen on the socket*/
if(listen(sockfd, BACKLOG) == -1) {
perror("fail to listen");
exit(1);
}
printf("Success to listen on the socket...\n");
while(1) {
sinSize = sizeof(struct sockaddr_in);
/*accept a client's request*/
if ((clientfd = accept(sockfd,
(struct sockaddr *)&clientSockaddr, &sinSize)) == -1) {
perror("fail to accept");
exit(1);
}
printf("success to accept=======\n");
/*改变打印颜色*/
printf("\033[40;32mWelcome to join %s!\033[1m\n",
inet_ntoa(clientSockaddr.sin_addr));
/* 创建线程实现信号传递 */
pthread_create(&tid, NULL, deal_msg, &clientfd);
}
return 0;
}
/*********客户端.c***************/
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include "comm.h"
#define SERVPORT 1234
#define MAX_DATA_SIZE 3096
int main(int argc, char *argv[])
{
int sockfd, sendBytes,recvBytes;
char sendBuf[MAX_DATA_SIZE],recvBuf[MAX_DATA_SIZE];
struct hostent *host;
struct sockaddr_in servAddr;
msg_head_t *msg;
// int ret;
if(argc != 2) {
fprintf(stderr,"usage:./client [hostname]");
exit(1);
}
/*translate the address*/
if((host = gethostbyname(argv[1])) == NULL) {
perror("fail to get host by name");
exit(1);
}
printf("Success to get host by name...\n");
/*establish a socket*/
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("fail to establish a socket");
exit(1);
}
printf("Success to establish a socket...\n");
/*init sockaddr_in*/
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(SERVPORT);
servAddr.sin_addr = *((struct in_addr *)host -> h_addr);
bzero(&(servAddr.sin_zero), 8);
/*connect the socket*/
if(connect(sockfd, (struct sockaddr *)&servAddr,
sizeof(struct sockaddr_in)) == -1) {
perror("fail to connect the socket");
goto _exit;
}
printf("Success to connect the socket...\n");
printf("\033[40;32mWelcome to join %s!\033[1m\n",
inet_ntoa(servAddr.sin_addr)); //include color set
while(1) {
/*send datas to server*/
printf("Client:");
gets(sendBuf);
sendBytes = strlen(sendBuf);
msg = (msg_head_t *)malloc(sizeof(msg_head_t) + sendBytes + 1);
memset(msg, 0, sizeof(msg_head_t) + sendBytes + 1);
msg->len = sendBytes;
printf("===msg_len [%d]\n", msg->len);
strncpy(msg->data, sendBuf, strlen(sendBuf));
printf("==data is: %s\n", msg->data);
send(sockfd, msg, sizeof(msg_head_t) + msg->len + 1, 0);
}
_exit:
close(sockfd);
}
/***************结构体头文件.h**********/
#ifndef _COMM_H_
#define _COMM_H_
typedef struct msg_head_s{
int type;
int len;
char data[0];
}msg_head_t;
#endif
I/O多路复用
- 作用:它能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态。处理多个套接字使用
- 基本函数
Select()函数可以帮助你同时监视许多套接字。它会告诉你哪一个套接字已经可以读取数据,哪个套接字已经可以写入数据,甚至你可以知道哪个套接字出现了错误 - 相关宏
FD_ZERO(fd_set *set)将一个文件描述符集合清零
FD_SET(int fd, fd_set *set)将文件描述符fd 加入集合set 中。
FD_CLR(int fd, fd_set *set)将文件描述符fd 从集合set 中删除.
FD_ISSET(int fd, fd_set *set)测试文件描述符fd 是否存在于文件描述符set 中.