TCP服务端
一、创建Socket套接字
1.头文件
#include <sys/types.h>
#include <sys/socket.h>
2.功能:Socket()为通信创建一个端点,并返回一个描述符。
3.函数原型
int socket(int domain, int type, int protocol);
参数
Domain 设置为AF_INET IPv4 因特网协议
Type 设置为SOCK_STREAM 使用TCP协议,提供有序的、可靠的、双向的、基于连接的字节流。
Protocal 设置为0,0选择type类型对应的默认协议
5.返回值
错误返回-1。
二、BindIP号端口号与相应描述字赋值函数
1.功能:用于绑定IP地址和端口号到socketfd
函数原型
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
2.参数
Sockfd是一个socket描述符
Addr
是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针,指向要绑定给sockfd的协议地址结构,这个地址结构根据地质创建socket时的地址协议族的不同而不同。
Ipv4对应的是:
Struct sockaddr_in{
Sa_family sin_family; //协议族
in_port_t sin_port;//端口号
Struct in_addr sin_addr;//IP地址结构体
Unsigned char sin_zero[8];//填充,无实际意义,只是为跟sockaddr结构在内存中对齐,这样两者才能相互转换//
};
Addrlen 指定addr所指向的地址结构的大小(以字节为单位)。
3.返回值
成功返回0,失败返回-1
4.地址转换API
int inet_aton(const char* straddr,struct in_addr *addrp);
把字符串形式的“192.168.1.123”转为网络能识别的格式
char* inet_ntoa(struct in_addr inaddr);
把网络格式的ip地址转为字符串形式
5.字节序转换api
头文件
#include <netinet/in.h>
API
uint16_t htons(uint16_t host16bitvalue); //返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue); //返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue); //返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue); //返回主机字节序的值
h代表host,n代表net,s代表short(两个字节),l代表long(4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取。
6.字节序转换与地址转换代码
struct sockaddr_in s_addr;
Struct
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));//主机字节序和网络字节序之间的转换
inet_aton(argv[1],&s_addr.sin_addr);//把IP地址转为网络能识别的格式
三、监听设置函数Listen
1.功能:将一个未连接的套接字转换为一个被动套接字(监听),规定内核为相应套接字排队的最大连接数
2.函数原型
int listen(int sockfd, int backlog);
参数
Sockfd
socket描述符
Backlog
指定在请求队列中允许的最大请求数 ,这里设置为10
四、接收链接Accept
1.功能:accept函数由TCP服务器调用 ,用于从已完成连接队列队头返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入睡眠。
2.函数原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数
Sockfd
socket描述符
Addr 用来返回已连接的客户端的协议地址
Addrlen 客户端地址长度
3.返回值
成功返回已连接的套接字描述符,失败返回-1
五、数据收发
1.头文件
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
2.函数说明:read()会把参数fd所指的文件传送count 个字节到buf 指针所指的内存中。
3.返回值:返回值为实际读取到的字节数, 如果返回0, 表示已到达文件尾或是无可读取的数据。若参数count 为0, 则read()不会有作用并返回0。
ssize_t write(int fd, const void *buf, size_t count);
函数说明:write()会把参数buf所指的内存写入count个字节到参数放到所指的文件内。write成功返回,只是buf中的数据被复制到了kernel中的TCP发送缓冲区
返回值:如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。
服务端代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
int main(int argc,char **argv)
{
int s_fd;
int c_fd;
int n_read;
char readBuf[128] = {0};
// char *msg = "I get your connect";
char msg[128] = {0};
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
if(argc != 3){
printf("param error\n");
exit(-1);
}
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.sockey
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
//2.bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
listen(s_fd ,10);
//4.accept
int client = sizeof(struct sockaddr_in);
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&client);
if(c_fd == -1){
perror("accept");
}
printf("get connect: %s\n",inet_ntoa(c_addr.sin_addr));
if(fork() == 0){
if(fork() == 0){
while(1){
//6.write
memset(msg,0,sizeof(msg));
printf("input data: ");
gets(msg);
write(c_fd,msg,strlen(msg));
}
}
while(1){
//5.read
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd,readBuf,128);
if(n_read == -1 ){
perror("read");
}else{
printf("get message:%d,from client:%s\n",n_read,readBuf);
}
}
}
}
//7.close
//close(s_fd);
return 0;
}
TCP客户端
六、创建socket套接字(略)
七、connect客户端连接主机
函数原型
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
1.功能:用于绑定之后的client(客户端)与服务器建立连接
2.参数
Sockfd
Socket描述符
Addr是服务器端的IP地址和端口号的地址结构指针
Addrlen
地址长度常被设置为sizeof(struct sockaddr)
3.返回值
成功返回0,失败返回-1.
八、数据收发(略)
客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
int main(int argc,char **argv)
{
int c_fd;
int n_read;
char readBuf[128] = {0};
// char *msg = "message from client";
char msg[128] = {0};
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
if(argc != 3){
printf("param error\n");
exit(-1);
}
//1.sockey
c_fd = socket(AF_INET,SOCK_STREAM,0);
if(c_fd == -1){
perror("socket");
exit(-1);
}
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&c_addr.sin_addr);
//4.connect
int c_net = connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr));
if(c_net == 1){
perror("connect");
exit(-1);
}
while(1){
if(fork() == 0){
while(1){
//5.send
memset(msg,0,sizeof(msg));
printf("input data: ");
gets(msg);
write(c_fd,msg,strlen(msg));
}
}
while(1){
//6.read
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd,readBuf,128);
if(n_read == -1){
perror("read");
}else{
printf("get message form server:%d,%s\n",n_read,readBuf);
}
}
}
//7.close
close(c_fd);
return 0;
}