Linux socket 基础函数及使用范例

 

以c语言开发的socket通信

 

首先Linux环境下的服务器端:

 

#include<sys/socket.h>
int socket(int domain,int type,int protocol);

说明:
1 成功时返回一个整型的Socket描述符,失败时返回-1
2 domain:套接字中使用的协议族信息(protocol family)
常用的两个:PF_INET :IPv4互联网协议族
PF_INET6:IPv6互联网协议族
3 type:套接字类型(数据传输方式)
具有代表性的两个:
SOCK_STREAM:面相连接的套接字,流式,面向连接的比特流,顺序、可靠、双向,用于TCP通信
SOCK_DGRAM :面向消息的套接字,数据报式,无连接的,定长、不可靠、常用语于UDP通信
4 protocol:最终决定采用的协议。一般情况下为0;除非同一个协议族中存在多个传输方式相同的协议时,需要具体指定

 

例子:
1 IPv4协议族中面向连接的套接字(TCP套接字)

 

int tcp_socket = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);

2 IPv4协议族中面向消息的套接字(UDP套接字)

int udp_socket = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);

 

 

int bind(int sockfd,struct sockaddr *myaddr,socklen_t addrlen);

说明:
1 将套接字与指定端口相连,成功返回0,失败返回-1
2 sockfd:前面调用socket()函数返回的文件描述符
3 struct sockaddr *myaddr:指向sockaddr结构体的指针(该结构体中保存有端口和IP地址信息)
4 socklen_t addrlen:指定了以addr所指向的地址结构体的字节长度

 

int listen(int sockfd,int backlog);

说明:
1 监听连接请求,成功返回0,失败返回-1
2 sockfd 处于监听状态,并且最多允许有backlog个客户端处于连接待状态
 

int accept(int sockfd,struct sockaddr *myaddr,socklen_t *addrlen)

说明:
1 服务器调用accept()接受连接,如果没有客户端的连接请求就阻塞等待直到有客户端连接上
2 成功则返回一个新的套接字用于连接,与客户端进行点对点的通信
3 sockfd:用于监听的文件描述符,即第一次socket()函数产生的
4 sockaddr *myaddr:传出参数,存有连接好的客户端的IP地址和端口信息,设为NULL表示不关心
5 sockaddr *addrlen:传入传出参数,传入的是调用者提供的缓冲区myaddr的长度以避免缓冲区溢出问题。传出的是客户端
地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)如果给cliaddr参数传NULL表示不关心客户端的地址
 

int close(int filedes);

说明:关闭套接字

其次,客户端:

 

 

int socket(int domain,int type,int protocol);

同上:
 

int connect(int sockfd,struct sockaddr *serv_addr,socklen_t addrlen);

说明:
1 连接服务器,成功返回0,失败返回-1
2 struct sockaddr *serv_addr:服务器的IP地址和端口信息

 

 

int close(int filedes);


对于Linux而言,socket是文件的一种,因此读写文件同样适用于socket
写文件:

#include<unistd.h>
//typedef unsigned int size_t
//typedef signe4 int ssize_t 
ssize_t write(int fd,const void *buf,size_t nbytes);

 

 

说明:
1 成功返回写入的字节数,失败返回-1
2 int fd:文件描述符
3 const void *buf:保存写入数据的缓冲区
4 size_t nbytes:要传输数据的字节数

读文件:

 

ssize_t read(int fd,void *buf,size_t nbytes);

1 成功返回接受的字节数(但遇到文件结尾则返回0),失败则返回-1
2 int fd:文件描述符
3 const void *buf:保存接收数据的缓冲区
4 size_t nbytes:要接受数据的最大字节数

收发数据函数:

 

TCP:

 

int send(SOCKET s,const char FAR *buf,int len,int flags); 

说明:
1 SOCKET s:接受套接字
2 const char FAR *buf:发送数据缓冲区
3 int len:实际发送的长度(字节数)
4 int flags:该参数一般置0;
其他参数:
MSG_DONTROUTE:绕过路由表查找
MSG_DONTWAIT:此操作非阻塞
MSG_OOB:发送带外数据
5 成功则返回实际发送字节数,失败则返回SOCKET_ERROR

 

 

 

int recv(SOCKET s,char FAR *char,int len,int flags);

说明:
1 SOCKET s:接受套接字
2 char FAR * char:接受缓冲区
3 int len:接受缓冲区长度
4 int flags:该参数一般置0;
其他参数:
MSG_DONTWAIT:此操作非阻塞
MSG_OOB:接受带外数据
MSG_PEEK:窥看外来信息
MSG_WAITALL:等待所有数据
5 成功则返回实际发送字节数,失败则返回SOCKET_ERROR
 

UDP:
	int sendto(int sockfd,const void *msg,int len unsigned int flags,const struct sockaddr *to,int tolen);

说明:
1 该函数比send()多了两个参数:
2 const struct sockaddr *to:指向目的机的IP地址和端口信息
3 int tolen:struct sockaddr 的大小
 

int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);

说明:
1 int sockfd:接受套接字
2 void *buf:接受缓冲区
3 int len:接受缓冲区长度
4 unsigned int flags:同recv()
5 struct sockaddr *from:信息来源机的地址信息
6 int *fromlen:struct sockaddr的大小

使用范例:

 

 

//Server
	#include<stdio.h>
	#include<stdlib.h>
	#incldue<string.h>
	#incldue<unistd>
	#incldue<arpa/inet.h>
	#incldue<sys/socket.h>
	void error_handing(char *message);
	
	int main(int argc,char *argv[])
	{
		int serv_sock;
		int clnt_sock;
		
		struct sockaddr_in serv_addr;
		struct sockaddr_in clnt_addr;
		socklen_t clnt_addr_size;
		
		char message[] = "Hello World!";
		
		if(argc != 2)		//提示输入端口
		{
			printf("Usage :%s <port>\n",argv[0]);
			exit(1);
		}
		
		serv_sock = socket(PF_INET,SOCK_STREAM,0);
		if(serv_sock == -1)
			error_handing("socket() error!\n");
		
		memset(serv_addr,0,sizeof(serv_addr)); 
		//void *memset(void *s,int c,size_t n)
		//将已开辟内存空间 s 的首 n 个字节的值设为值 c
		serv_addr.family = AF_INET;
		serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
		serv_addr.sin_port = htons(atoi(argv[1]));
		
		if(bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) == -1)
			error_handing("bind() error");
		
		if(listen(serv_sock,5) == -1)
			error_handing("listen() error");
		
		clnt_addr_size = sizeof(clnt_addr);
		clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_addr,&clnt_addr_size);
		if(clnt_sock == -1)
			error_handing("accept() error");
		
		write(clnt_sock,message,sizeof(message));
		return 0;
	}
	
	void error_handing(char *message)
	{
		fputs(message,stderr); //stderr为标准错误输出,在屏幕上输出由当前文件名和这条调用所在的行号组成的信息
		fputc('\n',stderr);
		exit(1);
	}

 

 

//Client
	#include<stdio.h>
	#include<stdlib.h>
	#incldue<string.h>
	#incldue<unistd>
	#incldue<arpa/inet.h>
	#incldue<sys/socket.h>
	void error_handing(char *message);
	
	int main(int argc,char* argv[])
	{
		int sock;
		struct sockaddr_in serv_addr;
		char message[30];
		int str_len;
		
		if(argc != 3)
		{
			printf("Usage :%s <IP><Port>\n",argv[0]);
			exit(1);
		}
		
		sock = socket(PF_INET,SOCK_STREAM,0);
		if(sock == -1)
			error_handing("sock error!\n");
		
		memset(&serv_addr,0,sizeof(serv_addr));
		serv_addr.sin_family = AF_INET;
		serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
		serv_addr.sin_port = htons(atoi(argv[2]);
		
		if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) == -1)
			error_handing("connect() error!\n");
		
		str_len = read(sock,message,sizeof(message)-1);
		if(str_len == -1)
			error_handing("read error!\n");
		
		printf("Message from server: %s \n",message);
		close(sock);
		return 0;
	}
	
	void error_handing(char *message)
	{
		fputs(message,stderr);
		fputc('\n',stderr);
		exit(1);
	}

 

 

注:

 

 

 

struct sockaddr_in //该结构体针对Ipv4
{
	sa_family_t	 	sin_family;
	uint16_t		sin_port;
	struct in_addr  sin_addr;
	char 			sin_zero[8];
}

struct in_addr
{
	In_addr_t		s_addr;
}

struct sockaddr   //此结构不止针对Ipv4
{
	sa_family_t		sin_family;
	char			sa_data[14];
}

网络字节序,即大端序,网络传输统一用大端序
htons htonl ntohl ntohs


字符串转32位大端序整型值
in_addr_t inet_addr(const char * string);
 

 

在转换的同时自动加入sin_addr结构体中
char* addr = "127.232.124.79"
struct sockaddr_in addr_inet
inet_aton(addr,&addr_inet.sin_addr)

 

//WSAStringToAddress、WSAAddressToString用于windows中IP地址与字符串的转换
#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<WinSock2.h>

int _tmain(int argc, _TCHAR* argv[])
{
	char *strAddr = "196.168.1.154:8000";

	char strAddrBuff[50];
	SOCKADDR_IN servAddr;
	int size;
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	size = sizeof(servAddr);
	WSAStringToAddress(strAddr, AF_INET, NULL, (SOCKADDR*)&servAddr, &size);

	size = sizeof(strAddrBuff);
	WSAAddressToString((SOCKADDR*)&servAddr, sizeof(servAddr), NULL, strAddrBuff,(DWORD*)&size);

	printf("Second conv result:%s \n", strAddrBuff);
	WSACleanup();
	system("pause");
	return 0;
}

//accept()在客户端connect()之前为阻塞状态。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值