c socket编程
1、UDP
(1)client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#define REMOTEPORT 4567
#define REMOTEIP "127.0.0.1"//这是server端的IP,如在两台机器上测试,只需更改此IP为server端IP
/*
所在头文件:#include <strings.h>
函数原型:extern void bzero(void *s, int n);
函数功能:置字节字符串s的前n个字节为零且包括‘\0’。
入口参数:字符串,整型。
出口参数:无返回值。
*/
/*
所在头文件:#include <arpa/inet.h>
函数原型:in_addr_t inet_addr(const char *cp);
函数功能:将一个点间隔地址转换成一个in_addr。
入口参数:点间隔地址字符串。
出口参数:in_addr 型地址。
*/
/*
所在头文件:#include <unistd.h>
函数原型:ssize_t read(int fd, void *buf, size_t count);
函数功能:从文件流描述符fd中读数据到buf中,长度不超过count
入口参数:文件流描述符,缓存,长度
出口参数:读到的字符总长度。
*/
/*
所在头文件:#include < sys/types.h > #include < sys/socket.h >
函数原型:int sendto (int s,void * msg,int len, unsigned int flags,struct sockaddr *to,int tolen);
函数功能:将本机编号为s的套接字字符串msg发送给to套接字结构体所代表的地址及端口;
入口参数:s--socket编号,msg--需要发送的字符串,len--发送的字符串长度,flags--一般置0,to--套接子结构体类型,tolen--套接字结构体长度;
出口参数:传送成功,返回传送的字符个数;失败,返回-1。
*/
int main(int argc,char *argv[])
{
int s,len;
struct sockaddr_in addr;//套接字数据类型,用来存放一个套接字,这里是目的套接字
int addr_len;
char msg[256];
int i=0;
/*if else创建本地即客户端套接字*/
if(( s = socket(AF_INET,SOCK_DGRAM,0))<0) //创建套接字,返回套接字编号
{
perror("error");
exit(1);
}
else
{
printf("socket created successfully!\n");
printf("socket id:%d\n",s);
printf("remote ip:%s\n",REMOTEIP);
printf("remote port: %d\n\n",REMOTEPORT);
}
/*if else创建本地即客户端套接字*/
addr_len=sizeof(struct sockaddr_in);
bzero(&addr,sizeof(addr));
/*外地即服务端套接字*/
addr.sin_family=AF_INET;
addr.sin_port=htons(REMOTEPORT);
addr.sin_addr.s_addr=inet_addr(REMOTEIP);
/*外地即服务端套接字*/
while(1)
{
bzero(msg,sizeof(msg));
printf("Please Input message\n");
printf("The serial number of the message:%d\n",i);
i++;
len=read(STDIN_FILENO,msg,sizeof(msg));//从键盘(终端)键入msg
sendto(s,msg,len,0,(struct sockaddr *)&addr,addr_len);//发送msg给目的套接字addr
printf("Send message from client:%s",msg);
len=recvfrom(s,msg,sizeof(msg),0,(struct sockaddr *)&addr,&addr_len);//接受目的套接字传来的msg
printf("Received message from server:%s\n",msg);
}
}
(2)server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#define LOCALPORT 4567
int main(int argc,char *argv[])
{
int mysock,len;
struct sockaddr_in addr;
int i=0;
char msg[256];
int addr_len;
/*创建本地即服务端套接字*/
if((mysock=socket(AF_INET,SOCK_DGRAM,0))<0)
{
perror("error");
exit(1);
}
else
{
printf("socket created successfully!\n");
printf("socked id:%d\n",mysock);
}
/*创建本地即服务端套接字*/
addr_len=sizeof(struct sockaddr_in);
bzero(&addr,sizeof(addr));
/*本地即server套接字属性*/
addr.sin_family=AF_INET;
addr.sin_port=htons(LOCALPORT);
addr.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY 0.0.0.0 即将地址清零,系统找到的是本机IP
/*本地即server套接字属性*/
/*绑定本地server套接字的端口和IP*/
if(bind(mysock,(struct sockaddr *)&addr,sizeof(addr))<0)
{
perror("error");
exit(1);
}
else
{
printf("bind successfully!\n");
printf("local port:%d \n\n",LOCALPORT);
}
/*绑定本地server套接字的端口和IP*/
while(1)
{
bzero(msg,sizeof(msg));
len=recvfrom(mysock,msg,sizeof(msg),0,(struct sockaddr *)&addr,&addr_len);
printf("The serial number of the message:%d\n",i);
i++;
printf("The message Received from client:%s",msg);
printf("Received message length:%d\n",len);
printf("Received message from:%s\n",inet_ntoa(addr.sin_addr));
printf("Reply message from server:%s\n",msg);
sendto(mysock,msg,len,0,(struct sockaddr *)&addr,addr_len);
}
}
2.TCP
(1)client.c
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PORT 5678
#define REMOTE_IP "127.0.0.1"
int main()
{
int s;
struct sockaddr_in addr;
char mybuffer[256];
if((s=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket");
exit(1);
}
else
{
printf("socket created successfully!.\n");
printf("socked id:%d\n",s);
}
bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(PORT);
addr.sin_addr.s_addr=inet_addr(REMOTE_IP);
if(connect(s,(struct sockaddr *)&addr,sizeof(addr))<0)
{
perror("connect");
exit(1);
}
else
{
printf("connected ok!\n");
printf("remote ip:%s\n",REMOTE_IP);
printf("remote port:%d\n",PORT);
}
recv(s,mybuffer,sizeof(mybuffer),0);
printf("%s\n",mybuffer);
while(1)
{
bzero(mybuffer,sizeof(mybuffer));
read(STDIN_FILENO,mybuffer,sizeof(mybuffer));//从键盘读信息
/*发送并接收数据(if else意思是发送成功则执行接收,发送失败则退出)*/
if(send(s,mybuffer,sizeof(mybuffer),0)<0)//发送从键盘读到的信息
{
perror("send");
exit(1);
}
else
{
bzero(mybuffer,sizeof(mybuffer));
recv(s,mybuffer,sizeof(mybuffer),0);//接收server端的信息
printf("received from server:%s\n",mybuffer);
}
/*发送并接收数据(if else意思是发送成功则执行接收,发送失败则退出)*/
}
}
(2)
server.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 5678
#define MAX 10
/*面向连接套接字server端*/
/*
所在头文件:#include <sys/select.h>
函数原型:int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
函数功能:一个进程同时处理多个文件描述符是很常见的情况。
入口参数:
出口参数:1、正常情况返回就绪的文件描述符个数;2、timeout时长无设备准备好,返回0;3、若select被某个信号中断,返回-1,并设置errno为EINTR;4、若出错,则返回-1,并设置相应的errno。
*/
int main()
{
int sockfd,newsockfd,is_connected[MAX],fd;
struct sockaddr_in addr;
int addr_len = sizeof(struct sockaddr_in);
fd_set myreadfds;//定义文件描述符集合
char msgbuffer[256];
char msg[]="The message is from server:connected successfully.\n";
/*创建本地套接字*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket");
exit(1);
}
else
{
printf("socket created successfully!\n");
printf("socket id:%d\n",sockfd);
}
/*创建本地套接字*/
/*允许地址重用*/
int ret,on;
on=1;
ret=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
/*允许地址重用*/
/*本地套接子属性*/
bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(PORT);
addr.sin_addr.s_addr=htonl(INADDR_ANY);
/*本地套接子属性*/
/*绑定本地套接子端口和IP等属性*/
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
{
perror("connect");
}
else
{
printf("connected successfully!\n");
printf("local port:%d\n",PORT);
}
/*绑定本地套接子端口和IP等属性*/
/*server监听,等待client连接,最大连接数为3*/
if(listen(sockfd,3)<0)
{
perror("listen");
exit(1);
}
else
{
printf("listening......\n");
}
/*server监听,等待client连接,最大连接数为3*/
for(fd=0;fd<MAX;fd++)
{
is_connected[fd]=0;
}
while(1)
{
FD_ZERO(&myreadfds);//文件描述符集合中所有位置0
FD_SET(sockfd,&myreadfds);//将文件描述符的sockfd位置1(本地套接字位置1)
for(fd=0;fd<MAX;fd++)
{
if(is_connected[fd])
{
FD_SET(fd,&myreadfds);
}
}
if(!select(MAX,&myreadfds,NULL,NULL,NULL))
{
continue;
}
for(fd=0;fd<MAX;fd++)
{
if(FD_ISSET(fd,&myreadfds))
{
if(sockfd==fd)
{
if((newsockfd=accept(sockfd,(struct sockaddr *)&addr,&addr_len))<0)
{
perror("accept");
}
write(newsockfd,msg,sizeof(msg));//给客户端发送信息
is_connected[newsockfd]=1;
printf("connect from%s\n",inet_ntoa(addr.sin_addr));
}
else
{
bzero(msgbuffer,sizeof(msgbuffer));
if(read(fd,msgbuffer,sizeof(msgbuffer))<=0)
{
printf("connect closed.\n");
is_connected[fd]=0;
close(fd);
}
else
{
write(fd,msgbuffer,sizeof(msgbuffer));
printf("message:%s\n",msgbuffer);
}
}
}
}
}
}
(3)运行
gcc –o client.exe client.c
gcc –o server.exe server.c
在两个终端分别运行./client.c ./server.c
client.c终端输入字符串
且先运行server
套接字函数介绍
1、socket函数
#include <sys/socket.h>
int socket(int family,int type,int protocol);
功能:
创建一个套接口
入口:
family——指明协议族,一般是AF_INET(IPv4协议);
type——有SOCK_STREAM、SOCK_DGRAM、SOCK_SEQPACKET、SOCK_RAW;
protocol——IPPROTO_TCP IPPROTO_UDP IPPROTO_SCTP
出口:
正确,套接字字符描述符,非负整数;出错,-1