HTTP POST yapmanın ve yanıtı tüketmenin basit C örneği


92

HTTP gönderisi yapan çok basit bir C uygulaması oluşturmak istiyorum. Birkaç parametre alacak ve bunları bir URL oluşturmak için kullanacaktır. Ben sadece basit bir HTTP POST yapmak istiyorum ve cevabı curl kullanmadan almak istiyorum (kütüphaneler makineye yüklenmez ve çalıştırılmayacaktır).

Sözde kod:

  1. İşlem 2 bağımsız değişken

  2. Bağımsız değişkenleri şablon URL'sine yerleştirin: http://api.somesite.com/apikey=ARG1&command=ARG2

  3. Oluşturulan URL'de POST yap

  4. Yanıtı tüket

Google ve SO aramalarım bu konuda hiçbir sonuç vermedi.


2
Herhangi bir tür ağ çerçevesi kullanıyor musunuz? Hangi işletim sistemini kullanıyorsunuz?
cnicutar

Sadece temel bir Fedora veya Cent kutusu olacak. Ağ çerçeveleri olağan sys / socket, netdb, arpa / inet'tir. Sadece libcurl değil.
kmarks2

1
Libcurl değil. Başka bir kitaplık ile gitmek ister misiniz yoksa tamamen POSIX mi olmak zorunda?
cnicutar

Ne yazık ki tüm POSIX. Herhangi bir sistem üzerinde tamamen bağımsız olması gerekir.
kmarks2

2
Sizin için hazırladığım bir örnek var ama mesajın gövdesi yoksa neden POST kullandığınızı anlamıyorum. Tüm parametreler sorgu dizesindeyse neden bir GET yapmak istemiyorsunuz?
Jerry Jeremiah

Yanıtlar:


196

Bir iletinin bir başlık bölümü ve boş bir satırla ayrılmış bir ileti gövdesi vardır. Mesaj gövdesi olmasa bile boş satır HER ZAMAN gereklidir. Başlık bir komutla başlar ve iki nokta üst üste ve boşlukla ayrılmış ek anahtar değer çiftleri satırlarına sahiptir. Bir mesaj gövdesi varsa, olmasını istediğiniz herhangi bir şey olabilir.

Başlıktaki satırlar ve başlığın sonundaki boş satır, bir carraige dönüş ve satır besleme çifti ile bitmelidir (bkz. HTTP başlık satırı kesme stili ), bu nedenle bu satırların sonunda \ r \ n bulunur.

Bir URL şu şekildedir: http://host:port/path?query_string

Bir web sitesine istek göndermenin iki ana yolu vardır:

  • GET: Sorgu dizesi isteğe bağlıdır, ancak belirtilirse makul ölçüde kısa olmalıdır. Bu nedenle başlık sadece GET komutu olabilir ve başka bir şey olamaz. Örnek bir mesaj şöyle olabilir:

  • POST: Normalde sorgu dizesinde olan şey bunun yerine mesajın gövdesindedir. Bu nedenle, başlığın Content-Type: ve Content-Length: özniteliklerinin yanı sıra POST komutunu da içermesi gerekir. Örnek bir mesaj şöyle olabilir:

Öyleyse, sorunuzu yanıtlamak için: POST ile ilgilendiğiniz URL http://api.somesite.com/apikey=ARG1&command=ARG2 ise, gövde veya sorgu dizesi yoktur ve sonuç olarak, POST için bir neden yoktur çünkü mesajın gövdesine konulacak bir şey değildir ve bu nedenle Content-Type: ve Content-Length'e hiçbir şey konulamaz:

Sanırım gerçekten istersen POST yapabilirsin. Bu durumda mesajınız şöyle görünür:

Yani C programının ihtiyacı olan mesajı göndermek için:

  • bir soket oluştur
  • IP adresini ara
  • soketi aç
  • isteği gönder
  • cevabı bekle
  • soketi kapat

Gönderme ve alma çağrıları, onlara verdiğiniz TÜM verileri mutlaka göndermez / almaz - gerçekte gönderilen / alınan bayt sayısını döndürür. Onları bir döngü içinde aramak ve mesajın geri kalanını göndermek / almak size kalmıştır.

Bu örnekte yapmadığım şey herhangi bir tür gerçek hata kontrolüdür - bir şey başarısız olduğunda programdan çıkıyorum. Sizin için işe yarayıp yaramadığını bana bildirin:

Diğer yanıtın işaret ettiği gibi, 4096 bayt çok büyük bir yanıt değildir. İsteğinize verilen yanıtın kısa olacağını varsayarak bu sayıyı rastgele seçtim. Büyük olabilirse iki seçeneğiniz vardır:

  • yanıttan Content-Length: başlığını okuyun ve ardından tüm yanıtı tutmak için yeterli belleği dinamik olarak ayırın.
  • Parçalar geldikçe yanıtı bir dosyaya yazın

Yorumlarda sorulan soruyu cevaplamak için ek bilgiler:

Mesajın gövdesindeki verileri POST yapmak isterseniz ne olur? Ardından, Content-Type: ve Content-Length: başlıklarını eklemeniz gerekir. İçerik Uzunluğu: Başlığı gövdeden ayıran boş satırdan sonraki her şeyin gerçek uzunluğudur.

İşte aşağıdaki komut satırı bağımsız değişkenlerini alan bir örnek:

  • ev sahibi
  • Liman
  • komut (GET veya POST)
  • yol (sorgu verileri dahil değil)
  • sorgu verileri (GET için sorgu dizesine ve POST için gövdeye yerleştirin)
  • üstbilgi listesi (Content-Length: POST kullanılıyorsa otomatiktir)

Öyleyse, orijinal soru için koşarsınız:

Ve yorumlarda sorulan soru için:

İşte kod:


Çağrıldığında hangi argümanlar iletilmelidir?
Santiago Martí Olbrich

İlk parametre olarak apikey olarak kullanılacak ve ikinci parametrede komut olarak kullanılacak bir şeyi iletmeniz gerekir. Tamamen farklı bir sorgu dizisi kullanmak istiyorsanız, biçim dizesini, parametre sayısını ve kullanım mesajını değiştirmeniz gerekir.
Jerry Jeremiah

2
Bu kod, hatalı biçimlendirilmiş bir HTTP isteği yayar. HTTP, istek satırlarının satır başı / satır besleme çiftleri ( \r\n) ile sonlandırılması gerektiğini belirtir , ancak bu kod çıplak satır beslemelerini kullanır.
John Bollinger

@JohnBollinger Bu çok doğru. Gösterdiğiniz için teşekkürler. Umarım düzenlenmiş cevap daha iyidir.
Jerry Jeremiah

Bu gönderi mesajının nesi var? "POST /variableName=%s&value=%s HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 4\r\n\r\n\r\n"Name = reaz gibi göndermek istiyorum. 400 Kötü İstek yanıtlıyor
Reaz Murshed

12

Jerry'nin cevabı harika. Ancak, büyük yanıtları işlemez. Bunu halletmek için basit bir değişiklik:


3
Örneğimdeki yanıt dizisini daha büyük yapabilirsiniz. Bence sadece bazı json geri başlamıştı ve büyük bir dosya indirme değildi ama elbette bile json sorgusuna bağlı olarak megabayt ... olabilir üstlendiğini
Jerry Jeremiah

1
Ben C acemiyim ve cevabınız doğru olabilir. Ama lütfen cevabınıza bir açıklama ekleyebilir misiniz?
12'de boop

2
Bu gerçekten sadece kabul edilen cevapla ilgili bir yorumdur ve ayrı bir cevap verme girişimi olarak yapılmamalıydı.
Michael Gaskill

1
Buraya eklenecek tek bir şey var, bu harika çalışıyor ancak arabellek boyutunu - 1 bayt okumalısınız. Ve bunu düzgün bir şekilde görmek için, bu print cümlesinde bir satırsonu kullanmam. Şu şekilde görünmeli:bytes = recv(sockfd, response, 1023, 0)
xjsc16x

11

Haftalar süren araştırmalardan sonra. Aşağıdaki kodu buldum. Sanırım bu, bir web sunucusuna SSL ile güvenli bir bağlantı kurmak için gereken asgari düzeydedir.

Yukarıdaki kod, uzak bir sunucuyla bir TLS bağlantısının nasıl kurulacağını ayrıntılı olarak açıklayacaktır.

Önemli not : Bu kod, genel anahtarın geçerli bir yetkili tarafından imzalanıp imzalanmadığını kontrol etmez. Doğrulama için kök sertifika kullanmıyorum. Bu kontrolü uygulamayı unutmayın, aksi takdirde doğru web sitesine bağlanıp bağlanmadığınızı bilemezsiniz

İsteğin kendisine gelince. HTTP isteğini elle yazmaktan başka bir şey değildir.

Ayrıca bu bağlantı altında , sisteminize openSSL'yi nasıl yükleyeceğiniz ve güvenli kitaplığı kullanması için kodu nasıl derleyeceğiniz hakkında bir açıklama bulabilirsiniz .


2
Güzel Açıklama!
Satyam Koyani

hayır, sonraki değişken bağlantı noktasıdır, zaten doğru bağlantı noktasına bağlanıyoruz.
David Gatti

3

Kulp eklendi.
Ana bilgisayar başlığı eklendi.
Linux / windows desteği eklendi, test edildi (XP, WIN7).
UYARI: HATA: bağımsız değişken olarak ana bilgisayar, yol veya bağlantı noktası yoksa "bölümleme hatası".

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.