@TCP网络编程及函数详解
server:TCP传输(面向连接的可靠传输)
socket/bind/listen/accept/send/recv 头文件
#include <sys/types.h>
#include <sys/socket.h>
1.socket
int socket(int domain, int type, int protocol);
1)domain参数:一般是AF_INET
Name Purpose Man page
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
2)type参数:SOCK_STREAM (TCP)、SOCK_DGRAM (DUP)
3)protocol参数:一般填0即可
RETURN VALUE:成功返回一个新的socket,错误返回-1
2.bind
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
1)sockfd参数:创建socket返回的文件句柄(即文件描述符)
2)*addr参数:绑定服务端的 struct sockaddr_in ServerAddr;
sockaddr_in结构体定义:
struct sockaddr_in {
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
struct in_addr
{
unsigned long s_addr;
}
unsigned char sin_zero[8];
}
sin_family:一般为AF_INET
sin_port:需要监听的端口号
sin_addr:设置为INADDR_ANY表示可以和任何主机通信
sin_zero:填充作用
3)socklen_t addrlen参数:地址结构的长度,一般是sizeof(struct sockaddr)
RETURN VALUE:成功返回一个0,错误返回-1
3.listen监听
int listen(int sockfd, int backlog);
1)sockfd参数:创建socket返回的文件句柄(即文件描述符)
2)backlog参数:最多监听个数
RETURN VALUE:成功返回0,失败返回-1
4.accept建立连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
1)sockfd参数:创建socket返回的文件句柄(即文件描述符)
2)*addr参数:接收客户端的 struct sockaddr_in ClientAddr;;
3)socklen_t *addrlen参数:
一般是int addrlen=sizeof(struct sockaddr),然后取地址&addrlen
RETURN VALUE:成功返回一个非负整数,即接收套接字的文件描述符,失败返回-1
5.send发送/recv接收
1)ssize_t send(int sockfd, const void *buf, size_t len, int flags);
sockfd参数:文件描述符
buf参数: 可定义一个 char *cSendBuf[1024],用于存储发送数据
len参数: 发送数据的长度 //strlen(cSendBuf)
flags参数:一般填0即可
RETURN VALUE:成功返回发送的字节数,错误返回-1
2)ssize_t recv(int sockfd, void *buf, size_t len, int flags);
sockfd参数:文件描述符
buf参数: 可定义一个 char *cRecvBuf[1024],用于接收数据
len参数: 接收数据的长度
flags参数:一般填0即可
RETURN VALUE:成功返回接收的字节数,错误返回-1
6.IP处理函数
1)inet_aton //把ASCLL码ip转化为网络ip
int inet_aton(const char *cp, struct in_addr *inp);
返回如果地址有效,则为非零;如果无效,则为零。
2)inet_ntoa //inet_ntoa将网络IP转化为ASCLL码
char *inet_ntoa(struct in_addr in);
6.处理僵死进程
头文件 #include <signal.h>
sighandler_t signal(int signum, sighandler_t handler);
signal(SIGCHLD, SIG_IGN);
/*Server.c*/
#include <stdio.h>
//socket/bind/listen/accept/send/recv
#include <sys/types.h>
#include <sys/socket.h>
//inet_ntoa
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//memset
#include <string.h>
//fork
#include <unistd.h>
//signal
#include <signal.h>
#define SERVER_PORT 5555 //端口号
#define BACKLOG 5 //监听最多个数
int main(int argc, char *argv[])
{
int Server_fd; //server 描述符
int Client_fd; //client 描述符
int Ret1,Ret2;
int RecvLen;
int AddrLen;
int ClientNum = -1;
unsigned char cRecvBuf[1024];
struct sockaddr_in ServerAddr; //ServerAddr:用于存放服务端IP和端口号等
struct sockaddr_in ClientAddr; //ClientAddr:用于存放客户端IP和端口号等
//处理僵死进程函数
signal(SIGCHLD, SIG_IGN);
//创建socket
Server_fd = socket(AF_INET, SOCK_STREAM, 0); //IPV4、TCP
if(Server_fd == -1)
{
printf("Server_fd socket error!\n");
return -1;
}
bzero(&ServerAddr, sizeof(struct sockaddr_in));
ServerAddr.sin_family = AF_INET; //IPV4
ServerAddr.sin_port = htons(SERVER_PORT); //htons():把主机字节序转化为网络字节序
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY表示可以和任何主机通信
//memset(ServerAddr.sin_zero, 0, 8);
//绑定ServerAddr
Ret1 = bind(Server_fd, (const struct sockaddr *)&ServerAddr, sizeof(struct sockaddr));
if(Ret1 == -1)
{
printf("bind error!\n");
return -1;
}
//监听连接
Ret2 = listen(Server_fd, BACKLOG); //BACKLOG监听最多个数
if(Ret2 == -1)
{
printf("bind error!\n");
return -1;
}
//等待并接收连接
while(1)
{
printf("Waiting......\n");
AddrLen = sizeof(struct sockaddr);
//accept返回一个socket
Client_fd = accept(Server_fd, (struct sockaddr *)&ClientAddr, &AddrLen);
if(Client_fd != -1) //表示连接成功
{
ClientNum ++;
//inet_ntoa将网络IP转化为ASCLL码
printf("Get connet from client %d: %s!\n", ClientNum, inet_ntoa(ClientAddr.sin_addr));
if(fork() == 0) //子进程
{
while(1)
{
//接收客户端数据保存到cRecvBuf并打印输出,Client_fd-->cRecvBuf
RecvLen = recv(Client_fd, cRecvBuf, 1023, 0);
if(RecvLen <= 0)
{
printf("recv ClientData failed!\n");
close(Client_fd);
return -1;
}
else
{
cRecvBuf[RecvLen] = '\0'; //结束标志
printf("Get Msg from Client %d:%s\n", ClientNum, cRecvBuf);
}
}
}
// else //主进程(父进程)
// {
// }
}
}
close(Server_fd);
return 0;
}
/*client.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#define SERVER_PORT 5555 //端口号
int main(int argc, char *argv[])
{
int Client_fd; //client 描述符
int Ret;
struct sockaddr_in ServerAddr;
unsigned char cSendBuf[1024]; //发送缓冲区
int SendLen;
if(argc != 2)
{
printf("%s :please input <server_ip>!\n", argv[1]);
return -1;
}
//创建socket
Client_fd = socket(AF_INET, SOCK_STREAM, 0); //IPV4、TCP
if(Client_fd == -1)
{
printf("Client_fd socket error!\n");
return -1;
}
bzero(&ServerAddr, sizeof(struct sockaddr_in));
ServerAddr.sin_family = AF_INET; //IPV4
ServerAddr.sin_port = htons(SERVER_PORT); //htons():把主机字节序转化为网络字节序
//ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY表示可以和任何主机通信
if(inet_aton(argv[1], &ServerAddr.sin_addr) == 0) //把argv[1]的ASCLL码ip转化为网络ip
{
printf("invalid server_ip!\n");
return -1;
}
//memset(ServerAddr.sin_zero, 0, 8);
Ret = connect(Client_fd, (const struct sockaddr *)&ServerAddr, sizeof(struct sockaddr));
if(Ret == -1)
{
printf("connet error!\n");
return -1;
}
while(1)
{
if(fgets(cSendBuf, 1023, stdin)) //从标准输入获取数据并发送到
{
//通过Client_fd发送给服务端,cSendBuf-->Client_fd
SendLen = send(Client_fd, cSendBuf, strlen(cSendBuf), 0);
if(SendLen <= 0)
{
printf("client senddata failed!\n");
close(Client_fd);
return -1;
}
}
}
close(Client_fd);
return 0;
}